I need ListView in Delphi with colored column headers. Using VCL Styles is not the option.
After checking the two topics:
I have defined TMyListView that draw colored column headers.
My problem is: I can not find out how to draw the same color after last column (the space between right border of the last column and the right side of the ListView).
Here is small test with my TMyListView:
unit Unit1;
interface
uses
Winapi.Windows, Winapi.Messages, Winapi.CommCtrl,
System.SysUtils, System.Variants, System.Classes, Vcl.Graphics,
Vcl.Controls, Vcl.Forms, Vcl.Dialogs, Vcl.ComCtrls;
type
TMyListView = class(TCustomListView)
private
FHeaderHandle: HWND;
FHeaderColor: TColor;
FHeaderFontColor: TColor;
function WMNotifyHeaderDraw(var AMessage: TWMNotify): boolean;
protected
procedure CreateWnd; override;
Procedure WMNotify(var Msg: TWMNotify); message WM_NOTIFY;
public
constructor Create(AOwner: TComponent); override;
destructor Destroy; override;
end;
type
TForm1 = class(TForm)
procedure FormCreate(Sender: TObject);
procedure FormDestroy(Sender: TObject);
private
{ Private declarations }
FMyListView: TMyListView;
procedure CreateMyListView();
public
{ Public declarations }
end;
var
Form1: TForm1;
implementation
{$R *.dfm}
//------------------ TMyListView-----------------
constructor TMyListView.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
FHeaderColor := clOlive;
FHeaderFontColor:= clYellow;
end;
procedure TMyListView.CreateWnd;
begin
inherited;
FHeaderHandle := GetWindow(handle, GW_CHILD);
end;
destructor TMyListView.Destroy;
begin
inherited Destroy;
end;
procedure TMyListView.WMNotify(var msg: TWMNotify);
begin
if (FHeaderColor <> clNone) then
begin
if WMNotifyHeaderDraw(msg) then exit;
end;
inherited;
end;
function TMyListView.WMNotifyHeaderDraw(var AMessage: TWMNotify): boolean;
const
DT_ALIGN: array[TAlignment] of integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
var
fontColor: TColor;
NMCustomDraw: TNMLVCustomDraw;
b: TBrush;
hitemRect: TRect;
columnIndex: integer;
columnCaption: string;
begin
result := false;
if (AMessage.NMHdr.hwndFrom = FHeaderHandle) and
(AMessage.NMHdr.code = NM_CUSTOMDRAW) then
begin
result := true;
NMCustomDraw := PNMLVCustomDraw(TMessage(AMessage).LParam)^;
case NMCustomDraw.nmcd.dwDrawStage of
CDDS_PREPAINT:
begin
AMessage.Result := CDRF_NOTIFYITEMDRAW;
end;
CDDS_ITEMPREPAINT:
begin
fontColor := Font.Color;
b := TBrush.Create;
try
hitemRect := NMCustomDraw.nmcd.rc;
columnIndex := NMCustomDraw.nmcd.dwItemSpec;
SelectObject(NMCustomDraw.nmcd.hdc, b.Handle);
b.Color := clLtGray; // separator
FillRect(NMCustomDraw.nmcd.hdc, Rect(hitemRect.Right-1, hitemRect.Top, hitemRect.Right, hitemRect.Bottom), b.Handle);
b.Color := FHeaderColor; // header background
FillRect(NMCustomDraw.nmcd.hdc, Rect(hitemRect.Left, hitemRect.Top, hitemRect.Right-1, hitemRect.Bottom), b.Handle);
finally
b.Free;
end;
if FHeaderFontColor <> clNone then
fontColor := FHeaderFontColor;
SetTextColor(NMCustomDraw.nmcd.hdc, ColorToRGB(fontColor));
SetBKMode(NMCustomDraw.nmcd.hdc, TRANSPARENT);
Inc(hitemRect.Left,4);
Dec(hitemRect.Right,4);
if self.Column[columnIndex].Alignment = taLeftJustify then Inc(hitemRect.Left,6)
else Dec(hitemRect.Right,6);
columnCaption := self.Column[columnIndex].Caption;
DrawTextW(NMCustomDraw.nmcd.hdc, pWideChar(columnCaption),
length(columnCaption), hitemRect,
DT_SINGLELINE or DT_ALIGN[self.Column[columnIndex].Alignment] or
DT_VCENTER or DT_END_ELLIPSIS);
AMessage.Result := CDRF_SKIPDEFAULT;
end;
else
AMessage.Result := CDRF_DODEFAULT;
end;
end;
end;
//----------------- TForm1-------------------------------------
procedure TForm1.FormCreate(Sender: TObject);
begin
CreateMyListView();
end;
procedure TForm1.FormDestroy(Sender: TObject);
begin
FreeAndNil(FMyListView);
end;
procedure TForm1.CreateMyListView();
var cl: TListColumn;
begin
if not Assigned(FMyListView) then begin
FMyListView := TMyListView.Create(self);
FMyListView.Parent := self;
FMyListView.Align := alClient;
FMyListView.ViewStyle := vsReport;
FMyListView.DoubleBuffered := true;
cl := FMyListView.Columns.Add();
cl.Caption := 'Column 1';
cl.Width := 200;
cl.Alignment := taLeftJustify;
cl.Tag := 0;
cl := FMyListView.Columns.Add();
cl.Caption := 'column 2';
cl.Width := 250;
cl.Alignment := taLeftJustify;
cl.Tag := 1;
cl := FMyListView.Columns.Add();
cl.Caption := 'column 3';
cl.Width := 150;
cl.Alignment := taRightJustify;
cl.Tag := 2;
FMyListView.RowSelect := true;
//FMyListView.FullDrag := true;
FMyListView.Items.Add.Caption := 'Item1';
FMyListView.Items.Add.Caption := 'Item2';
FMyListView.Items[0].SubItems.Add('11-22');
FMyListView.Items[0].SubItems.Add('11-33');
FMyListView.Items[1].SubItems.Add('2222-22');
FMyListView.Items[1].SubItems.Add('2222-33');
end;
end;
end.
Can someone please help me to solve the problem?
Many thanks.
Add after the last column an extra column:
The
cl.AutoSizeproperty makes it follow the width of theListViewand the other columns, but doesn't force the scrollbar to appear, except if the fixed sized columns start to shrink.There is a minor draw back, if you show row lines, they will also show in the extra column, but that was not an issue in your example.