8

Using either TTreeView.OnAdvancedCustomDrawItem or TTreeView.CustomDrawItem, how does one completely draw an tree view item? There is no sample code on the docwiki for the Advanced custom draw item.

The Delphi documentation wiki has a confusing sample that references code that does not exist in the sample, and does not compile. I take it that the problem is split into three separate painting issues:

  1. Get the theme element for the Windows tree view node and draw it.
  2. Get any image that exists in the node and paint it.
  3. Draw the text for the node.

Finally, one should set DefaultDraw := false so that the control doesn't do the default painting for the node.

It seems to me that such a basic thing should exist as a real working sample somewhere, but the closest I have found, is the documentation wiki which just says "See this other thing" and provides no link to the rest of the code.

The non-working sample with rather too much hand-waving and incomplete code, references some things that are not defined in this demo, but were obviously cut and pasted from a working sample. Some of the changes one would make are obvious (like define your own way to get the colors for the brush, and your own way to decide what font the node should be), and some are not, like how to implement DrawButton:

procedure TCustomDrawForm.TVCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode;
  State: TCustomDrawState; var DefaultDraw: Boolean);
var
  NodeRect: TRect;
begin
  with TV.Canvas do
  begin
{
    If DefaultDraw it is true, any of the node's font 
    properties can be changed. Note also that when 
    DefaultDraw = True, Windows draws the buttons and 
    ignores our font background colors, using instead the
    TreeView's Color property.
}
    if cdsSelected in State then
    begin
      Font.Assign(SelectedFontDialog.Font);
      Brush.Color := SelBkgColorDialog.Color;
    end;

    DefaultDraw := False; // FDefaultDrawItem;
{
    DefaultDraw = False means you have to handle all the
    item drawing yourself, including the buttons, lines,
    images, and text.
}
    if not DefaultDraw then
    begin
      //draw the selection rect.
      if cdsSelected in State then
      begin
        NodeRect := Node.DisplayRect(True);
        FillRect(NodeRect);
      end;
      NodeRect := Node.DisplayRect(False);

      if None1.Checked then
      //no bitmap, so paint in the background color.
      begin
        Brush.Color := BkgColorDialog.Color;
        Brush.Style := FBrushStyle;
        FillRect(NodeRect)
      end
      else
        //don't paint over the background bitmap.
        Brush.Style := bsClear;

      NodeRect.Left := NodeRect.Left + (Node.Level * TV.Indent);
      // NodeRect.Left now represents the left-most portion 
      // of the expand button
      DrawButton(NodeRect, Node); // See the CustomDraw demo

      NodeRect.Left := NodeRect.Left + TV.Indent + FButtonSize;
      //NodeRect.Left is now the leftmost portion of the image.
      DrawImage(NodeRect, Node.ImageIndex); // See the CustomDraw demo

      NodeRect.Left := NodeRect.Left + ImageList.Width;
      //Now we are finally in a position to draw the text.

      TextOut(NodeRect.Left, NodeRect.Top, Node.Text);
    end;
  end;
end;
Warren P
  • 65,725
  • 40
  • 181
  • 316
  • Related but incomplete and not quite the same: http://stackoverflow.com/questions/10930695/how-to-draw-ttreeviews-styled-selection-rectangle-during-advancedcustomdrawitem – Warren P Jul 22 '13 at 17:27
  • You should look for some sample code in C++ – David Heffernan Jul 22 '13 at 17:31
  • 1
    The only variables not in scope that it uses are `FDefaultDrawItem`, which is simply a Boolean from the form's `private` section, initialized to `True` in the `FormCreate` event. It's toggled to `True/False` in a checkbox `OnClick` event handler, after which time the `TreeView.Repaint` method is called to trigger a redraw. The others are `None1.Checked` (a checkbox) and a `DrawButton` method (also in the sample).(You can see the full code if you have D2007 installed in the `Users\Public\Documents\RAD Studio\5.0\Demos\DelphiWin32\VCLWin32\CustomDraw\CustomDrawTreeView.pas` file.) – Ken White Jul 22 '13 at 17:37
  • Sorry, just double checked. The checks are provided by menu items, not checkboxes. They're both in the `Custom Drawing` menu. – Ken White Jul 22 '13 at 17:43
  • That demo is a huge help, but it's not usable for real world code. For example, it should be getting the Win32 bitmaps and using them, to draw the + and - expand/collapse nodes, but it just hacks up its own ones in a few lines of Win32 canvas line/circle code. – Warren P Jul 22 '13 at 17:54
  • Warren, you asked for a working example of using `OnCustomDrawItem`, which the demo code provides. Drawing the default bitmaps simply requires a call to `DrawThemeIcon` with the imagelist and image index to draw and the right `iPartID` and `iStateID` values for the portion and state of the item you're drawing. Is your question now no longer about `OnCustomDrawItem` and instead about drawing using themes? – Ken White Jul 22 '13 at 18:46
  • 1
    That's true. From the point of view of a real answer that is good on Stack Overflow, if nobody has a working example, I will write one and answer my own question. Seems a useful thing to have a sample of on StackOverflow. – Warren P Jul 22 '13 at 20:33
  • Warren, why trying to re-use win component just to totally override it ? why not TreeViewNT or even VTV ? – Arioch 'The Jul 23 '13 at 06:50
  • Have you ever tried to remove a TTreeView from a 5-million line app with 60K lines in every form? It could be a 3-5 week job. – Warren P Jul 23 '13 at 13:24

0 Answers0