6
votes

So, my end game here is to have a way to list items (like a TListView in vsReport) with the add/remove buttons inside the client area.

Ex:

|----------------|
|Old Item 1    X |
|Old Item 2    X |
|Add new item... |
|                |
|----------------|

If you know of a component that does this without all this extra work, please let me know!

So I picked out an red close "X" and am using a TJvTransparentButton (Jedi Components - JVCL) to display it. It handles the press/not pressed states and only shows the image. I original used a TButton but I didn't need all the fluff that goes around the glyph.

Now, I keep the image button in the record associated with each node.

Code is as follows:

procedure TfrmMain.AddNewAccount(const Username, Password: String);
var
  Data : PTreeData;
  XNode : PVirtualNode;
Begin
  XNode := vstAccounts.AddChild(nil);
  If vstAccounts.AbsoluteIndex(XNode) > -1 Then
    begin
    Data := vstAccounts.GetNodeData(Xnode);
    Data^.Column0 := Username;
    Data^.Column1 := '';
    Data^.DeleteButton := TJvTransparentButton.Create(nil);
    With Data^.DeleteButton Do
      begin
      Parent := vstAccounts;
      Left := 0;
      Top := 0;
      Width := 16;
      Height := 16;
      Anchors := [];
      AutoGray := False;
      BorderWidth := 0;
      FrameStyle := fsNone;
      Images.ActiveImage := iListView;
      Images.ActiveIndex := 0;
    end;
  end;
end;

In the OnAfterCellPaint event I manage the positioning of the image button like so:

procedure TfrmMain.vstAccountsAfterCellPaint(Sender: TBaseVirtualTree;
  TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
  CellRect: TRect);
var
  Data : PTreeData;
begin
  If Column = 1 Then
    begin
    Data := vstAccounts.GetNodeData(Node);
    If Assigned(Data) Then
      begin
      With Data^.DeleteButton Do
        begin
        BoundsRect := CellRect;
      end;
    end;
  end;
end;

Now the problem is that this doesn't show the item at all. I know that the Image from the TImageList is fine because I can create the button at design time and it looks fine at runtime.

I also know that this code should work because if I make the TJvTransparentButton a regular TButton (without changing the code logic) it works just fine and shows up fine!

The only thing I can think of is that a TButton inherits from a TWinControl while the TJvTransparentButton inherits from a TControl.

Any ideas?

2

2 Answers

3
votes

I assume the TJvTransparentButton is a TGraphicControl and as such is displayed as part of the Parent's background (that's why a Tlabel will always be behind a TEdit or TButton in the same Parent).
The TButton is a TWinControl and as such is painted on top of the Parent and above or below the other WinControls in the same Parent.

So, either, you paint yourself again the TJvTransparentButton after the regular drawing of the cell happened (updating BoundsRect is not enough) or you use a WinControl.
For instance, using a TPanel with the TJvTransparentButton in it should work.

Disclaimer: I'm not familiar with VirtualStringTree nor TJvTransparentButton ...

3
votes

You're doing this in a wrong way. You must write your own editor for TVirtualStringTree which implements IVTEditLink interface. Then in OnCreateEditor event you need to create your editor:

procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
begin
  EditLink:=TStringEditLink.Create;
end;

You can get more info here.