8

I have a TTreeView in Delphi, with nodes at three levels.

I use node data to store another label besides the node text.

Type
  TNodeData = class
    ExtraNodeLabel: WideString;
    //... other members
  end;

I have an OnAdvancedCustomDrawItem event, where i want to display this ExtraNodeLabel before the node text. I wish to achieve this:

  • The blue text would be the extra label.
  • higlighted item: first two words are also an extra label

enter image description here

What i got so far, is this:

enter image description here

Problems:

  1. For some reason i can't draw text with different style if i use DrawText/drawTextW (I need drawtextW because of unicode data)
  2. The other problem is, that anything outside the dotted focus rectangle is unclickable

What needs to be solved:

  1. How can i draw text with different style using DrawText/DrawtextW
  2. How can i make the whole text clickable?

Code:

procedure TMainForm.TntTreeView1AdvancedCustomDrawItem(
  Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState;
  Stage: TCustomDrawStage; var PaintImages, DefaultDraw: Boolean);
var
  txtrect, fullrect : TRect;
  DC: HDC;
  fs: integer;
  fc: TColor;
  ExtralabelRect: TRect;
  nData: TNodeData;
begin
  nData := nil;

  if assigned(Node.Data) then begin
    nData := TNodeData(Node.Data);
  end;

  DC := TntTreeView1.canvas.Handle;
  txtRect := Node.DisplayRect(True);    
  fullrect := Node.DisplayRect(False);

  if stage = cdPostPaint then begin
    TntTreeView1.Canvas.FillRect(txtRect);
    if (cdsFocused In State) And (cdsSelected in State) then begin
      DrawFocusRect(DC,txtRect);
    end;

    txtRect.Left := txtRect.Left + 1;
    txtRect.Top := txtRect.Top + 1;
    txtRect.Right := txtRect.Right - 1;
    txtRect.Bottom := txtRect.Bottom - 1;

    ExtralabelRect := txtRect;

    fs := TntTreeView1.Canvas.Font.size;
    fc := TntTreeView1.Canvas.Font.Color;

    if (nData <> nil) And (nData.ExtraNodeLabel <> '') then begin
      TntTreeView1.Canvas.Font.Size := 7;
      TntTreeView1.Canvas.Font.color := clBlue;
      DrawTextW(
        DC,
        PWideChar(nData.ExtraNodeLabel),
        Length(nData.ExtraNodeLabel),
        ExtraLabelRect,
        DT_LEFT or DT_CALCRECT or DT_VCENTER
      );

      DrawTextW(
        DC,
        PWideChar(nData.ExtraNodeLabel),
        Length(nData.ExtraNodeLabel),
        ExtraLabelRect,
        DT_LEFT or DT_VCENTER
      );

      txtRect.right := txtRect.Right + ExtraLabelRect.Right + 5;
      txtRect.Left := ExtraLabelRect.Right + 5;
    end;

    TntTreeView1.Canvas.Font.Size := fs;
    TntTreeView1.Canvas.Font.color := fc;

    DrawTextW(
      DC,
      PWideChar((Node as TTntTreeNode).Text),
      -1,
      txtRect,
      DT_LEFT or DT_VCENTER
    );
  end;
end;
Johan
  • 74,508
  • 24
  • 191
  • 319
beerwin
  • 9,813
  • 6
  • 42
  • 57
  • 2
    Your number 2 probably has to do with the fact that the tree measures the width of its node's text to determine the focus rectangle and that doesn't take your extra text into account. To solve that you would either have to add the text to the node's Text or create your own TTreeview descendant and find a way to override / hook into the width measurement for the focus rectangle (a quick read of the [documentation](http://docwiki.embarcadero.com/Libraries/XE4/en/Vcl.ComCtrls.TTreeView) doesn't bring up any obvious events). – Marjan Venema Jul 05 '13 at 13:01
  • 1
    It is as @Marjan says. There is nothing like `TVM_SETITEMRECT` nor `TVM_SETITEMHEIGHT`, notification message nor a macro for setting a node width. I'd say, you will need to set the `TTreeNode.Text` property value for proper extending of the node width. – TLama Jul 05 '13 at 13:36
  • Unfortunately i can't set the TTreeNode.Text property, as this value should not be saved together with the node text. – beerwin Jul 05 '13 at 13:44
  • Also, the first problem is more important, as if that can be solved, there might be no need for the second (i could play with the item height and use 2 different font sizes) – beerwin Jul 05 '13 at 13:45
  • what about VirtualTreeView ? – Arioch 'The Jul 05 '13 at 14:08
  • @TLama Yes, but i need to use different styles, so the prepaint stage is not going to work – beerwin Jul 05 '13 at 14:28
  • @Arioch 'The, VirtualTreeview is not an option, as this progam is a large project being developed for many years. __I would like to use it__, but replacing a control will take too much time and there are economic considerations. – beerwin Jul 05 '13 at 14:30
  • Custom painting in the comctl32 tree view control is very hard to get right. Good luck! – David Heffernan Jul 05 '13 at 14:37
  • Same for TreeNT ? did not tried it so dunno if its APi is vastly different from TreeView's... – Arioch 'The Jul 05 '13 at 15:56
  • @Arioch 'The: I wanted to tell you, that replacing the control is not an option here, my hands are tied. – beerwin Jul 05 '13 at 16:13

1 Answers1

2

Solution by the OP

I managed to partially solve custom drawing, by defining a TFont variable, and using SelectObject and setTextColor. Setting font color and style works, but setting the font size doesn't.

var 
  nFont: TFont;
begin
  DC := TntTreeView1.Canvas.Handle;
  NFont := TFont.Create;

  // rest of the code here ...

  // i tried to set nFont.Size, but it doesn't seem to work
  nFont.Size := 7;
  nFont.Color := colorToRGB(clBlue);
  nFont.Style := TntTreeview1.Font.Style + [fsBold];

  SelectObject(DC,NFont.Handle);
  SetTextColor(DC,colortoRGB(clBlue));

  DrawTextW(
    DC,
    PWideChar(nData.nodeLabel),
    Length(nData.nodeLabel),
    ExtraLabelRect,
    DT_LEFT or DT_VCENTER
  );

  // rest of the code here
end;

Source: I used the idea from here


Update 2

I solved the second problem by setting the treeview's RowSelect property to true. For this, to work, i had to set the ShowLines property to false, and custom draw the lines and the buttons. It works now.


Update 3

I improved the solution for the first problem, by not creating a new font, but selecting the canvas font for displaying text, and this way i was able to change any aspect of the font, and the system cleartype settings are also applied:

// set font size for the canvas font (font style can be set the same time)
TntTreeView1.Canvas.Font.Size := 7;

// select canvas font for DC
SelectObject(DC,TntTreeView1.Canvas.Font.Handle);

// set font color
SetTextColor(DC,colortoRGB(clBlue));
Johan
  • 74,508
  • 24
  • 191
  • 319