TListView columns header with defined color - how to color unused space of the header bar

479 Views Asked by At

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.

1

There are 1 best solutions below

1
Tom Brunberg On

Add after the last column an extra column:

cl := FMyListView.Columns.Add();
cl.AutoSize := True;

The cl.AutoSize property makes it follow the width of the ListView and 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.

enter image description here