We help IT Professionals succeed at work.

Changing Component Colours

Greystoke
Greystoke asked
on
Take for example a listview - you can change the background colour and the text colour.  How do I go about changing the colour of the Column Heading, and the Row Selection colour?  If at all possible that is.

Comment
Watch Question

Commented:
listening

Commented:
maybe you should download the advanced component from
www.tmssoftware.com

Commented:
Well, here may be part of the answer.  The row colors.  This does work.  I have a form with a listview on it.  Through the object inspector I put in two items, the first was Tony with a sub item of Miller and the second was Bob with a subitem of Curry.  I also changed the property Ownerdraw to true otherwise this won't work.


procedure TForm1.ListView1DrawItem(Sender: TCustomListView;
  Item: TListItem; Rect: TRect; State: TOwnerDrawState);
var
   s1 : string;
begin
   With tListview(Sender).Canvas do begin
      if (not odSelected in State) then begin
         s1 :=     item.Caption;
         s1 := lowercase(s1);
         if not (s1 = 'tony') then begin
            Brush.Color := clblack;
            Font.Color := clwhite;
         end else begin
            Brush.Color := clwhite;
            Font.Color := clblack;
         end;
      end;
      FillRect(Rect);
      textOut(Rect.Left, Rect.top, s1);
   end;
end;

Note that you can write code if odSelected is in the state thus allowing you to change to the sellection color.

As for the header, I don't know, maybe someone else will have an idea.

If you want this sample code let me know.

toe  

Commented:
Oops, this component doesn't accept textout when odselected in state though it appears to be ok when you first draw it.  

The not needs to be outside the '(' in the statement 'not(odselected in state)'  

Once Ondrawitem is used you do have to assign a color for  the odselected in state case as it appears this component doesn't allow you to not assign it and the component has a default.  

And, finally, it only works on the report view.

Perhaps there is a better answer.

toe

Commented:
I know I'd seen something like this :). Anyway, I've got this snippet (not mine, but I forgot where I got it from, it's been awhile) that shows how to make the headers ownerDraw:

{Description
{HeaderHandle : HWND;}
HeaderHandle := GetDlgItem(ListView1.Handle, 0);

{Now that you have a handle to the header control, what you need to do is
change the header control to owner-drawn.  This is done with a call to
the SetHeader_Item API call...}

    hdi : HD_ITEM;

    for i := 0 to ListView1.Columns.Count - 1 do
    begin

        hdi.mask := HDI_TEXT and HDI_FORMAT and HDI_WIDTH;

        {Flag owner draw state}
        hdi.fmt := HDF_LEFT and HDF_OWNERDRAW and HDF_STRING;

        hdi.cxy := Columns.Items[i].Width;
        hdi.cchTextMax := Columns.Items[i].Caption.Length();

        hdi.pszText := Columns.Items[i].Caption;

        {Force the changes}
        Header_SetItem(HeaderHandle, index, hdi^);

    end

{Now that the headers are owner-drawn, Windows will send the ListView the
WM_DRAWITEM message which you have to trap in the ListView's WindowProc
(or a derived unit from TListView) and decode.  The LParam of the
WM_DRAWITEM message is a DRAWITEM structure.}

GL
Mike

Commented:
Some more digging & I found this snippet (Attr'ed to Damon Chandler):

uses
  Windows, Messages, SysUtils, Classes, Graphics, Controls,
  Forms, Dialogs, StdCtrls, ComCtrls, commctrl;

type
TForm1 = class(TForm)
    procedure FormCreate(Sender: TObject);
    procedure FormDestroy(Sender: TObject);
public
    HeaderHandle: HWND;
    ListView1: TListView;
    OldListViewWP: TWndMethod;
    procedure NewListViewWP(var Msg: TMessage);
    procedure DrawHeader(Index: integer; ARect: TRect;
                AState: integer; DC: HDC);
end;

var
  Form1: TForm1;

{$R *.DFM}
implementation
procedure TForm1.FormCreate(Sender: TObject);
var
    hdi: THDItem;
    i: Integer;
begin
    ListView1 := TListView.Create(self);
    ListView1.Parent := self;
    ListView1.ViewStyle := vsReport;
    ListView1.Columns.Add().Caption := 'Column 1';
    ListView1.Columns.Add().Caption := 'column 2';
    OldListViewWP := ListView1.WindowProc;
    ListView1.WindowProc := NewListViewWP;

    HeaderHandle := GetDlgItem(ListView1.Handle, 0);
    for i := 0 to ListView1.Columns.Count - 1 do
    begin
         hdi.mask := HDI_FORMAT;
        hdi.fmt := hdi.fmt or HDF_OWNERDRAW;
        Header_SetItem(HeaderHandle, i, hdi);
    end
end;

procedure TForm1.FormDestroy(Sender: TObject);
begin
    ListView1.WindowProc := OldListViewWP;
end;


procedure TForm1.NewListViewWP(var Msg: TMessage);
var
   dis: ^TDrawItemStruct;
   hdn: ^THDNotify;
begin
    if Msg.Msg = WM_DRAWITEM then
    begin
        dis := Pointer(Msg.LParam);
        DrawHeader(dis.ItemID, dis.rcItem,
                   dis.ItemState, dis.hDC);
        Msg.Result := 1;
    end
    else if Msg.Msg = WM_NOTIFY then
    begin
          hdn := Pointer(Msg.LParam);
        if hdn.hdr.code = HDN_ENDTRACK then
        begin
            Msg.Result := 0;
         InvalidateRect(HeaderHandle, nil, true);
        end;
        OldListViewWP(Msg);
    end
    else OldListViewWP(Msg);
end;


procedure TForm1.DrawHeader(Index: integer; ARect: TRect;
     AState: integer; DC: HDC);
var
   f : TFont;
   b : TBrush;
   p : TPen;
   s : string;
begin
     f := TFont.Create;
     b := TBrush.Create;
     p := TPen.Create;
     s := ListView1.Columns[Index].Caption;
     try
        f.Assign(Listview1.Font);
        f.Style := f.Style + [fsBold];
        b.Color := clBlue;
        SelectObject(DC, f.Handle);
        FillRect(DC, ARect, b.Handle);
        SetTextColor(DC, ColorToRGB(clYellow));
        SetBKMode(DC, TRANSPARENT);
        ARect.Left := ARect.Left + 5;
        DrawText(DC, PChar(s), Length(s), ARect, DT_LEFT);
     finally
        f.Free;
        b.Free;
        p.Free;
     end;
end;

end.

GL
Mike
For what it may be worth to you here is an example of how I did a "Quicken style" color bars in Delphi6.

Set ListView's Owner draw to false.
Activate the OnCustomDrawItem event.

procedure TForm1.ListView1CustomDrawItem(Sender: TCustomListView; Item: TListItem; State: CustomDrawState; var DefaultDraw: Boolean);
var
  ItemRect: TRect;
begin
  With TListview(Sender).Canvas do begin
        if Odd(Item.Index) then begin
           Brush.Color := clmoneygreen;
           Font.Color := clblack;
        end else begin
           Brush.Color := clWindow;
           Font.Color := clblack;
        end;

     DefaultDraw := False; //user draw
     ItemRect := Item.DisplayRect(drBounds);

      if Item.Selected then
       begin
        Brush.Color := clHighlight;
        Font.Color := clHighlightText;
        //Rectangle(Rect);
        //Font.Style:= [fsBold] else  Font.Style:= [];
       end;

     FillRect(ItemRect);
     DefaultDraw := True; // AI takes over
  end;
end;

Explore More ContentExplore courses, solutions, and other research materials related to this topic.