Add Getting fancy with TTreeView

Getting fancy with TTreeView
Overcoming certain problems when custom drawing tree nodes
By: Jody Dawkins

TTreeView has four events through which to facilitate custom drawing:
- OnCustomDraw
- OnCustomDrawItem
- OnAdvancedCustomDraw
- OnAdvancedCustomDrawItem

The implementation of these events work fine provided you are using them to produce relatively
simple changes in appearance. As long as you are only using one font per node everything
should be fine.

So what are you to do when you want to use multiple fonts in a single node?

You a number of solutions:
- Use a third-party components
- Write custom TTreeView to solve this problem
- Use the method I'll show here

This method is really a work-around. If you need a solid, high performance solution then you
should seek out a commercially available third-party component. That being said here is my

I needed to produce a "multi-line" tree view. This is to say each node would have more than
one line of text. As you know there is no OnMeasureItem as there is on TListBox and no way
to set the item height for each node. To overcome this I added a TImageList with the Height
property set to 48 and assigned it to the Images property of the TTreeView.

Now I just needed to paint each line in the OnCustomDrawItem event. I intended to make the
first line bold and the second line normal text colored with clAppWorkspace. After discovering
the problems inherit to this situation I decided to draw my text to a bitmap then draw the bitmap
on the TTreeView.

Here's the code:

  1. procedure TForm1.tvDesignViewCustomDrawItem(Sender: TCustomTreeView;
  2.   Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
  4.   procedure ChangeFont(Canvas : TCanvas; const NewColor : TColor; const
  5. NewStyle : TFontStyles);
  6.   begin
  7.     Canvas.Font.Style := NewStyle;
  8.     if not (cdsSelected in State) then
  9.       Canvas.Font.Color := NewColor
  10.     else
  11.       Canvas.Font.Color := clHighlightText;
  12.   end;
  14. var
  15.   txtrect, fullrect : TRect;
  16.   th : Integer;
  17.   s : string;
  18.   bmp : TBitmap;
  19.   TextLeft : Integer;
  20. begin
  21.   DefaultDraw := False;
  22.   txtrect := Node.DisplayRect(True);
  23.   fullrect := Node.DisplayRect(False);
  24.   txtrect.Right := fullrect.Right; // I want access to the rest of the
  25. space to the right
  26.   bmp := TBitmap.Create;
  27.   try
  28.     bmp.Height := txtrect.Bottom - txtrect.Top;
  29.     bmp.Width := txtrect.Right - txtrect.Left;
  30.     with bmp.Canvas do begin
  31.       Brush.Assign(Sender.Canvas.Brush);
  32.       Pen.Assign(Sender.Canvas.Pen);
  33.       Font.Assign(Sender.Canvas.Font);
  34.       FillRect(ClipRect);
  35.       TextLeft := 2;
  36.       ChangeFont(bmp.Canvas, clWindowText, [fsBold]);
  37.       th := TextHeight('Wg');
  38.       TextOut(TextLeft, 2, Node.Text);
  39.       ChangeFont(bmp.Canvas, clAppWorkSpace, []);
  40.       TextOut(TextLeft, 2 + (th * 1), ‘Here is line 1);
  41.       ChangeFont(bmp.Canvas, clWindowText, []);
  42.       TextOut(TextLeft, 2 + (th * 2), ‘Here is line 2);
  43.     end;
  44.     Sender.Canvas.Draw(txtrect.Left, txtrect.Top, bmp);
  45.   finally
  46.     FreeAndNil(bmp);
  47.   end;
  48. end;

Don’t forget: remember to add the TImageList as described above to create the space needed
for multiple lines.

This example could be further optimized by reusing the same TBitmap instead of creating and
destroying one each time the event is called.

Using this method you can fully customize the look of each node till your heart’s content. I found
it useful. I hope you will too.

- Jody
Related Discussions
  • FILETYPES... (2001-01-26 13:08:24)
    It will be easier if you get one of the free FileList and DriveList components from Torry's or DSP.
  • PRINTING TTREEVIEW ON QUICK REPORT (2001-02-21 09:23:24)
    Printing a TTreeView in not something trivial. It can be made of thousand of nodes, each of which possibly having thousand of subnodes, and so on....
    You have an access 2000 Database with a few table and are not very familiar with ADO. You want to, at least, connect you database to your...
  • HELP NEEDED WITH ITERATION (2001-03-15 09:05:13)
    Hi Chris, Glad it worked. It actually is VERY fast. I have a form (IO debugger) with something like 4000 labels on it. This method allows me...
  • ACCESS 2000 DATABASE PASSWORD (2001-03-27 02:07:45)
    You have an access 2000 Database with a few table and are not very familiar with ADO. You want to, at least, connect you database to your...
  • HOW I CAN DO DRAG AND DROP? (2001-04-01 04:09:09)
    This is a very simple way of doing it. unit Unit1; interface uses Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms,...
    First, thank you for access my web site. The OnDragDrop event returns an X,Y. You can then use GetNodeAt or GetHitTestInfoAt to figure out your...
  • TREEVIEW COMPONENT (2001-04-04 08:10:44)
    ... why is it sometimes i get this error when i add the component on a new form ? the control '' doesn't have any parent window
  • PROBLEM WITH TTREEVIEW (2001-04-10 13:34:19)
    Maybe you can search all the nodes that you wanna copy and save its name in an array, then you create nodes in another treeview with the names in...
  • NET QUESTION... (2001-05-18 18:24:10)
    The closest i could get to what you are thinking of is this: Note: I originally used this in an MDIclient and requires the TNetwork component by...
Latest News
Submit News Form Past News
Latest Forum Entries