Display extra text in treeview nodes, not just node.text
Asked Answered
Q

1

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;
Quintuplet answered 5/7, 2013 at 12:14 Comment(10)
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 doesn't bring up any obvious events).Capitol
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.Heavyduty
Unfortunately i can't set the TTreeNode.Text property, as this value should not be saved together with the node text.Quintuplet
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)Quintuplet
what about VirtualTreeView ?Lecture
@Heavyduty Yes, but i need to use different styles, so the prepaint stage is not going to workQuintuplet
@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.Quintuplet
Custom painting in the comctl32 tree view control is very hard to get right. Good luck!Lothario
Same for TreeNT ? did not tried it so dunno if its APi is vastly different from TreeView's...Lecture
@Arioch 'The: I wanted to tell you, that replacing the control is not an option here, my hands are tied.Quintuplet
U
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));
Unshackle answered 5/7, 2013 at 12:15 Comment(0)

© 2022 - 2024 — McMap. All rights reserved.