Sources
Delphi Russian Knowledge Base
DRKB - это самая большая и удобная в использовании база знаний по Дельфи в рунете, составленная Виталием Невзоровым

HeaderControl с дополнительной возможностью отображения стрелок

01.01.2007
////////////////////////////////////////////////////////////////////////////////
//
//  ****************************************************************************
//  * Unit Name : GSHeaderControl
//  * Purpose   : Обычный HeaderControl с дополнительной возможностью отображения стрелок
//  * Author    : Александр (Rouse_) Багель
//  * Version   : 1.00
//  ****************************************************************************
//

unit GSHeaderControl;
 
interface
 
uses
  Windows, Messages, SysUtils, Classes, Controls, ComCtrls, CommCtrl, Themes,
  Graphics;
 
const
  HDF_SORTDOWN = $0200;
  HDF_SORTUP = $0400;
 
type
  TGSSortDirection = (sdUp, sdDown);
  TGSHeaderControl = class(THeaderControl)
  private
    FSortSection: Integer;
    FSortDirection: TGSSortDirection;
    FUpDownBitmap: array [sdUp..sdDown] of TBitmap;
    procedure WMLButtonDown(var Message: TWMLButtonDown); message WM_LBUTTONDOWN;
    procedure SetSortDirection(const Value: TGSSortDirection);
    procedure SetSortSection(const Value: Integer);
  public
    constructor Create(AOwner: TComponent); override;
    destructor Destroy; override;
    // Отрисовка стрелок через эти 2 свойства
    // Секция в которой будем рисовать стрелку (для отключения стрелок, SortedSection := -1)
    property SortedSection: Integer read FSortSection write SetSortSection;
    // Направление стрелки (вверх - вниз)
    property SortDirection: TGSSortDirection read FSortDirection write SetSortDirection;
  end;
 
procedure Register;
 
implementation
 
procedure Register;
begin
  RegisterComponents('Samlpes', [TGSHeaderControl]);
end;
 
{ TGSHeaderControl }
 
constructor TGSHeaderControl.Create(AOwner: TComponent);
var
  I: TGSSortDirection;
begin
  inherited;
  FSortSection := -1;
  FSortDirection := sdDown;
  for I := sdUp to sdDown do
  begin
    FUpDownBitmap[I] := TBitmap.Create;
    FUpDownBitmap[I].Width := 14;
    FUpDownBitmap[I].Height := 14;
    FUpDownBitmap[I].Canvas.Brush.Color := clBtnFace;
    FUpDownBitmap[I].Canvas.Fillrect(Rect(0, 0, 14, 14));
    FUpDownBitmap[I].Canvas.Font.Size := 14;
    FUpDownBitmap[I].Canvas.Font.Name := 'Marlett';
  end;
  // Эти битматы для рисования стрелки при отключенных темах ХР
  FUpDownBitmap[sdUp].Canvas.TextOut(0, -2, #53);
  FUpDownBitmap[sdDown].Canvas.TextOut(0, -2, #54);
end;
 
destructor TGSHeaderControl.Destroy;
begin
  FUpDownBitmap[sdUp].Free;
  FUpDownBitmap[sdDown].Free;
  inherited;
end;
 
// Указываем направление стрелки (вверх - вниз)
procedure TGSHeaderControl.SetSortDirection(const Value: TGSSortDirection);
begin
  FSortDirection := Value;
  SetSortSection(FSortSection);
end;
 
// Включаем стили для отрисовки стрелок
procedure TGSHeaderControl.SetSortSection(const Value: Integer);
var
  Item: THDItem;
  PreviosSelected: Integer;
  Direction: Integer;
begin
  PreviosSelected := FSortSection;
  FSortSection := Value;
  if Sections.Count = 0 then Exit;
  if Value >= Sections.Count then Exit;
  // При включенных темах будем рисовать вот так:
  if ThemeServices.ThemesEnabled then
  begin
    if FSortDirection = sdUp then
      Direction := HDF_SORTUP
    else
      Direction := HDF_SORTDOWN;
    Item.Mask := HDI_FORMAT;
    // Убираем предыдущую стрелку
    if Header_GetItem(Handle, PreviosSelected, Item) then
      if (Item.fmt and HDF_SORTUP) = HDF_SORTUP then
      begin
        Item.fmt := Item.fmt xor HDF_SORTUP;
        Header_SetItem(Handle, PreviosSelected, Item);
      end;
      if (Item.fmt and HDF_SORTDOWN) = HDF_SORTDOWN then
      begin
        Item.fmt := Item.fmt xor HDF_SORTDOWN;
        Header_SetItem(Handle, PreviosSelected, Item);
      end;
    // Рисуем новую
    Item.Mask := HDI_FORMAT;
    Header_GetItem(Handle, FSortSection, Item);
    Item.fmt := Item.fmt or Direction;
    Header_SetItem(Handle, FSortSection, Item);
  end
  else
  begin // При выключенных темах, рисуем вот так:
    // Убираем предыдущую стрелку
    Item.Mask := HDI_FORMAT or HDI_BITMAP;
    Header_GetItem(Handle, PreviosSelected, Item);
    if (Item.fmt and HDF_BITMAP_ON_RIGHT) = HDF_BITMAP_ON_RIGHT then
      Item.fmt := Item.fmt xor HDF_BITMAP_ON_RIGHT;
    if (Item.fmt and HDF_BITMAP) = HDF_BITMAP then
      Item.fmt := Item.fmt xor HDF_BITMAP;
    Header_SetItem(Handle, PreviosSelected, Item);
    // Рисуем новую
    Item.Mask := HDI_FORMAT or HDI_BITMAP;
    Header_GetItem(Handle, FSortSection, Item);
    if (Item.fmt and HDF_BITMAP_ON_RIGHT) = HDF_BITMAP_ON_RIGHT then
      Item.fmt := Item.fmt xor HDF_BITMAP_ON_RIGHT;
    if (Item.fmt and HDF_BITMAP) = HDF_BITMAP then
      Item.fmt := Item.fmt xor HDF_BITMAP;
    Item.fmt := Item.fmt or HDF_BITMAP_ON_RIGHT or HDF_BITMAP;
    Item.hbm := FUpDownBitmap[FSortDirection].Handle;
    Header_SetItem(Handle, FSortSection, Item);
  end;
end;
 
// Включаем обработчик OnSectionClick при стиле hsFlat
procedure TGSHeaderControl.WMLButtonDown(var Message: TWMLButtonDown);
var
  Index: Integer;
  Info: THDHitTestInfo;
begin
  Info.Point.X := Message.Pos.X;
  Info.Point.Y := Message.Pos.Y;
  Index := SendMessage(Handle, HDM_HITTEST, 0, Integer(@Info));
 
  if (Index < 0) or (Info.Flags and HHT_ONHEADER = 0) or
    Sections[Index].AllowClick then
  begin
    inherited;
    if Style = hsFlat then
      if Index in [0 .. Sections.Count - 1] then
        Self.OnSectionClick(Self, Sections[Index]);
  end;
end;
 
 
end.

Взято из https://forum.sources.ru

Автор: Rouse_