1

I'm need to draw some graphics as node image. Like it draws images from ImageList in OnGetImageIndex event, but from the single source like TIcon, TImage, TBitmap.

In my situation all nodes have it own icons and places in UserData record.

How I can draw theese icons to nodes?

I found this code here, and tried to adept it for my situation:

procedure TForm10.Button1Click(Sender: TObject);
var
  Node: PVirtualNode;
begin
  VirtualStringTree1.AddChild(nil);
  Node := VirtualStringTree1.AddChild(nil);
  VirtualStringTree1.AddChild(Node);
  Node := VirtualStringTree1.AddChild(Node);
  VirtualStringTree1.AddChild(Node);
  VirtualStringTree1.AddChild(Node);
  VirtualStringTree1.AddChild(Node);
end;

procedure TForm10.VirtualStringTree1AfterItemPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; ItemRect: TRect);
var
  rImage: TRect;
  OffsetLeft: Integer;
  Icon: TIcon;
begin
  rImage := ItemRect;
  Icon := TIcon.Create;
  Icon.LoadFromFile('TestIcon_16.ico');
  with TVirtualStringTree(Sender) do
  begin
    if (toShowRoot in TreeOptions.PaintOptions) then
      OffsetLeft := Indent * (GetNodeLevel(Node) + 1)
    else
      OffsetLeft := Indent * GetNodeLevel(Node);

    Inc(rImage.Left, Margin + OffsetLeft);
    Inc(rImage.Top, (NodeHeight[Node] - Icon.Height) div 2);
    rImage.Right := rImage.Left + Icon.Width;
    rImage.Bottom := rImage.Top + Icon.Height;
  end;
  DrawIcon(TargetCanvas.Handle, rImage.Left, rImage.Top, Icon.Handle);
end;

After button click, I see that: enter image description here

Why that's happens? Icon size 100% - 16 x 16 px.

Where I can solve problem with drawning of text?

What I do wrong?

Ian Boyd
  • 246,734
  • 253
  • 869
  • 1,219
AlexLL
  • 165
  • 1
  • 13
  • Why it happens ? Because the tree doesn't know that you're doing that and doesn't indent node texts to make a space for your images. – TLama Jul 20 '14 at 10:33
  • How to notify it? Or exists any other idea to do this? – AlexLL Jul 20 '14 at 11:04
  • Since I don't have any expirience using this component I'm just guesing. But shouldn't you rather use OnBeforeItemPaint event instead. I asume that by using that event you might get a chance to controll the position of text so that it isn't drawn at the same place as your incons are. If nohing else you might be able to change the text by ading several empty spaces to it so it moves toward right. Doing this in OnAfterItemPaint event won't work becouse the text has already been painted at the time when event fires. – SilverWarior Jul 20 '14 at 11:35
  • 1
    Well, first of all you'll need to tell the tree to make some space. That's what you can do by increasing `Extent` parameter of the `OnMeasureTextWidth` event method. And then paint the text by yourself in the `OnDrawText` event method. But much better you'll go with default approach using image list. You can store those images into an image list and to each node store just index to that image list, don't you ? – TLama Jul 21 '14 at 07:39
  • Oh, and forgot to say, images that you've shown in your screenshot are not 16x16 px. They are bigger. – TLama Jul 21 '14 at 08:36
  • It can't be bigger. Under debugger I see Icon.Width/Height, it values equals to 16 px. – AlexLL Jul 21 '14 at 09:17
  • It's surely bigger. You can measure it on the picture. It's bigger. It seems to be 32x32 px. Besides, please use `@` char before the user name if you want to notify someone with comment (e.g. `@TLama`). We don't have to because you are the owner of the post and thus you are always notified. – TLama Jul 21 '14 at 09:32
  • 1
    You *see* a 32x32 icon for sure. it happens b/c you load 16x16 icon and draw it with `DrawIcon` which stretches it. you could use `DrawIconEx` or simply `TargetCanvas.Draw(x, y, Icon)`. in any case, you leaking memory of the TIcon, and I really don't see why you don't want to use an ImageList with `OnGetImageIndex` which is really the right way to go?... – kobik Jul 21 '14 at 11:17
  • @TLama, I know about leak, this is test project. In real TIcon stored in UserData, and releases when UserData is released. But what to do with the text? – AlexLL Jul 21 '14 at 12:22
  • [`This way`](http://pastebin.com/QuG8snNe) you can add a left indent to the node texts (assuming you are using LTR reading), but it's quite hacky way. I would still suggest using image list. – TLama Jul 22 '14 at 08:54
  • image list is perfect and already used, but user my install his own icon, nodes/chailds loads dynamically and it's many(> 1000). You think will be good recursive movearound all nodes to resetup icon, when user some delete, some add nodes? – AlexLL Jul 22 '14 at 09:41

1 Answers1

0

Unfortunately VT relies on image lists not allowing using separate images. In the same time, image lists are invconvenient as long as item insert and deletion is concerned. So as a workaround option you could create an image list for each image and return it to VT via OnGetImageEx event handler.

Alternatively, you can create one dummy image list with one empty and transparent image so that VT would know what dimensions the image has and paint your own custom images in AfterPaint.

Fr0sT
  • 2,959
  • 2
  • 25
  • 18