1
votes

An old app using Delphi 7, but should be similar code in older Delphi versions up to perhaps 2010. I need to change the background color of a TListView header so I can offer a dark theme. I can change the colors of everything else. I found the thread below which apparently works for changing the font color on a column header, but I need to adjust the background color of the entire header as well.

Delphi: ListView (vsReport) single column header caption with custom font color?

Can someone please help as I am lost. Windows message notifications are beyond my comprehension.

Many thanks.

1
After reading a documentation on Header Controls it seems there isn't an easy way to change the header background color. You would have to implement owner-drawing of header items by yourself.SilverWarior
The linked question provides two different ways to custom-draw column headers, one using NM_CUSTOMDRAW, the other using WM_DRAWITEM. The two codes are only setting the text color, but they both have access to the HDC that you can draw whatever you want on. For instance, using FillRect() with a brush of the desired color.Remy Lebeau
Thanks Remy. I implemented the NM_CUSTOMDRAW code and placed the following line of code above the SetColorText but it does nothing at all. FillRect(NMCustomDraw.hdc, NMCustomDraw.rc, COLOR_GRAYTEXT+1). The SetTextColor works though. Also tried SetBkColor with no effect. What am I missing?Ross
I managed to get the background colored using Message.Result := CDRF_SKIPDEFAULT rather than CDRF_NEWFONT and then use DrawText in code that I found elsewhere which handles left/right column alignment. However, there are no column dividers. I can drag invisible column dividers left and right. How would I draw those correctly? The left justified column title is being drawn too far to the left, and the right justified title is too far to the right, which I assume is due to the missing dividers.Ross

1 Answers

1
votes

I'm fairly proud of myself and somehow found bits and pieces of code that all went together to make it all work. Something like this...

procedure TTntListView.WMNotify(var AMessage: TWMNotify);
const
  DT_ALIGN: array[TAlignment] of integer = (DT_LEFT, DT_RIGHT, DT_CENTER);
var
  NMCustomDraw: TNMCustomDraw;
  i: Integer;
  r: TRect;
begin
  if (AMessage.NMHdr.hwndFrom = FHeaderHandle) and
    (AMessage.NMHdr.code = NM_CUSTOMDRAW) then
  begin
    NMCustomDraw := PNMCustomDraw(TMessage(AMessage).LParam)^;
    case NMCustomDraw.dwDrawStage of
      CDDS_PREPAINT: AMessage.Result := CDRF_NOTIFYITEMDRAW;
      CDDS_ITEMPREPAINT: begin
        i := NMCustomDraw.dwItemSpec;
        r := NMCustomDraw.rc;
        FillRect(NMCustomDraw.hdc, r, Sender.Canvas.Brush.Handle);
        SetBkColor(NMCustomDraw.hdc,  ColorToRGB(Sender.Canvas.Brush.Color));
        SetTextColor(NMCustomDraw.hdc, ColorToRGB(Sender.Canvas.Font.Color));
        DrawEdge(NMCustomDraw.hdc,r,EDGE_SUNKEN,BF_LEFT);
        Inc(r.Left,2);
        Dec(r.Right,2);
        if Sender.Column[i].Alignment = taLeftJustify then Inc(r.Left,3)
        else Dec(r.Right,3);
        DrawTextW(NMCustomDraw.hdc,
          pWideChar(Sender.Column[i].Caption),
          length(Sender.Column[i].Caption),
          r,
          DT_SINGLELINE or DT_ALIGN[Sender.Column[i].Alignment] or
            DT_VCENTER or DT_END_ELLIPSIS);
        Message.Result := CDRF_SKIPDEFAULT;
      end;
      else AMessage.Result := CDRF_DODEFAULT;
    end;
  end
  else inherited;
end;