Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

TTreeView custom draw of selected item

I'm trying to emulate Outlook 2013 left pane tree view menu for my application. I'm using CustomDraw because I only want to change some simple font and background properties.

Here's what I want:

Outlook 2013 sidebar menu

However, I always get the default selected drawing for both selected and hot tracked nodes. I don't have Windows 7 or XP to see if this is the normal behavior or if it's something related with my OS (Windows 8).

Here's what I'm getting:

Bad imitation of an Outlook 2013 style sidebar menu

Here's my code:

procedure TMainForm.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
  if Node.Level = 1 then
    Sender.Canvas.Font.Size := Sender.Canvas.Font.Size + 2;

  if cdsHot in State then
    Sender.Canvas.Brush.Color := $00F7E6CD
  else if (cdsSelected in State) or (cdsFocused in State) or
    (cdsChecked in State) then
    Sender.Canvas.Brush.Color := $00F2F2F2
  else
    Sender.Canvas.Brush.Color := $00DEDEDE;
  DefaultDraw := true;
end;

How can I draw a different colored background for selected and hot items?

like image 932
Leonardo Herrera Avatar asked Jul 08 '13 20:07

Leonardo Herrera


1 Answers

Try the following :

enter image description here

type
  TTreeView = class(Vcl.ComCtrls.TTreeView)
  protected
    procedure CreateWnd; override;
  end;


uses uxtheme;

procedure TTreeView.CreateWnd;
begin
  inherited;
  SetWindowTheme(Handle, nil , nil);
end;

procedure TForm1.FormCreate(Sender: TObject);
begin

   TreeView1.Font.Name := 'Segoe UI';
   TreeView1.HotTrack := True;
   TreeView1.Font.Size := TreeView1.Font.Size + 1;
   TreeView1.Color := $00DEDEDE;

end;

procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin

   if cdsFocused in State then begin
     Sender.Canvas.Brush.Color := $00F2F2F2;
     Sender.Canvas.Font.Color := clblack;
     Sender.Canvas.Font.Style := Sender.Canvas.Font.Style + [fsBold];
   end else if cdsHot in State then
    Sender.Canvas.Brush.Color := $00F7E6CD
   else
    Sender.Canvas.Brush.Color := $00DEDEDE;

end;

Explanation:

The Microsoft documentation on this is incredibly fuzzy, what I can say with certainty is that whenever an action (Selection, Hot tracking , De-Selection etc...) is performed on an Item (Node), a specific message is sent, this message includes the state of the Node via the parameters flag which at the very end internally decides how the Item should be updated visually based on the current Windows Theme.

This is the probable cause as to why disabling themes for the TreeView component removes the default selection rectangle & theme coloring. The documentation for the Control state flags supports this theory in partial.

like image 59
Peter Avatar answered Sep 28 '22 02:09

Peter