Recent

Author Topic: TreeView: Conflict between OnCustomDrawItem and HotTracking  (Read 569 times)

EganSolo

  • Sr. Member
  • ****
  • Posts: 389
I'm using a treeview component and assigned images to the nodes. Sadly, that hides the collapse/expand signs. Instead, I've implemented the OnCustomDrawItem to bold a node if it has children.
Code: Pascal  [Select][+][-]
  1. procedure TOptionsForm.TvCustomDrawItem(Sender         : TCustomTreeView ;
  2.                                         Node           : TTreeNode       ;
  3.                                         State          : TCustomDrawState;
  4.                                         var DefaultDraw: Boolean         );
  5. begin
  6.   If Node.Count > 0
  7.   then Sender.Canvas.Font.Style := [fsBold]
  8.   else Sender.Canvas.Font.Style := [];  
  9. end;    
  10.  

This works except if hot tracking is enabled, in which case, the bolding is ignored when the mouse hovers over the node and the text is underlined. Is the behavior hardwired in TTreeview, or is there a straightforward way to override it?

Jurassic Pork

  • Hero Member
  • *****
  • Posts: 1290
Re: TreeView: Conflict between OnCustomDrawItem and HotTracking
« Reply #1 on: June 04, 2025, 10:53:10 am »
Hello,
with hotTracking  , you can change the color of the text of a node but not attributes because hotTrack force underline and some other attributes of the font.
Example :
code (don't forget to put types in the uses ) :
Code: Pascal  [Select][+][-]
  1. procedure TForm1.tv_eg1CustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  2.   State: TCustomDrawState; var DefaultDraw: Boolean);
  3. var
  4.   R: TRect;
  5. begin
  6.    R := Node.DisplayRect(true);
  7.   if (PtInRect(R, sender.ScreenToClient(Mouse.CursorPos))) then
  8.   begin
  9.     If Node.Text = 'Root' then
  10.        begin
  11.          Sender.Canvas.Font.Color := clBlue;
  12.        end;
  13.     If Node.Text = 'Node1' then   Sender.Canvas.Font.Color := clRed;
  14.     If Node.Text = 'Node2' then   Sender.Canvas.Font.Color := clAqua;
  15.     If Node.Text = 'Node3' then   Sender.Canvas.Font.Color := clLime;
  16.   end;
  17. end;

Result in Attachment.

Friendly, J.P
Jurassic computer : Sinclair ZX81 - Zilog Z80A à 3,25 MHz - RAM 1 Ko - ROM 8 Ko

wp

  • Hero Member
  • *****
  • Posts: 13268
Re: TreeView: Conflict between OnCustomDrawItem and HotTracking
« Reply #2 on: June 04, 2025, 10:58:01 am »
Custom-drawing of the treeview has been quite buggy; this was fixed recently, hot-tracking is done by the theme-services now, but underlining is still possible when the theme-draw options is removed. Since this required some breaking changes it did not make it into v4.0 (https://wiki.freepascal.org/Lazarus_5.0_release_notes#TTreeView).

Working with a non-trunk version of Lazarus you can use the following workaround: Turn hot-tracking off and do it yourself. For this purpose you must redraw the tree with every mouse move when the mouse is over a different node. And in the OnCustomDrawItem handler you check whether the currently painted node is the same is the node under the mouse, and in this case you turn on underlining:

Code: Pascal  [Select][+][-]
  1.   TForm1 = class(TForm)
  2.     TreeView1: TTreeView;
  3.     procedure TreeView1CustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  4.       State: TCustomDrawState; var DefaultDraw: Boolean);
  5.     procedure TreeView1MouseMove(Sender: TObject; Shift: TShiftState; X,
  6.       Y: Integer);
  7.   private
  8.     FNodeUnderCursor: TTreeNode;
  9.     FPrevNodeUnderCursor: TTreeNode;
  10.   public
  11.  
  12.   end;
  13.  
  14. procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView;
  15.   Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
  16. begin
  17.   If Node.Count > 0
  18.   then Sender.Canvas.Font.Style := [fsBold]
  19.   else Sender.Canvas.Font.Style := [];
  20.  
  21.   if Node = FNodeUnderCursor then
  22.     Sender.Canvas.Font.Style := Sender.Canvas.Font.Style + [fsUnderline];
  23. end;
  24.  
  25. procedure TForm1.TreeView1MouseMove(Sender: TObject; Shift: TShiftState; X,
  26.   Y: Integer);
  27. begin
  28.   FNodeUnderCursor := (Sender as TTreeView).GetNodeAt(X, Y);
  29.   if FNodeUnderCursor <> FPrevNodeUnderCursor then
  30.   begin
  31.     TreeView1.Invalidate;
  32.     FPrevNodeUnderCursor := FNodeUnderCursor;
  33.   end;
  34. end;

In the trunk version your original code, however, would not work inspite of the customdrawing repair. This is because you set the Canvas.Font.style to [fsBold] or [] - and this removes the underlining state. If you change it as follows it would work in trunk, too:
Code: Pascal  [Select][+][-]
  1. procedure TForm1.TreeView1CustomDrawItem(Sender: TCustomTreeView; Node:
  2.   TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
  3. begin
  4.   If Node.Count > 0
  5.   then Sender.Canvas.Font.Style := Sender.Canvas.Font.Style + [fsBold]
  6.   else Sender.Canvas.Font.Style := Sender.Canvas.Font.Style - [fsBold];
  7. end;
« Last Edit: June 04, 2025, 10:59:35 am by wp »

EganSolo

  • Sr. Member
  • ****
  • Posts: 389
Re: TreeView: Conflict between OnCustomDrawItem and HotTracking
« Reply #3 on: June 07, 2025, 02:24:57 am »
wp: Thanks a lot! I'll follow through and report back!

 

TinyPortal © 2005-2018