I am using Delphi XE3 with Virtual Tree View.
My codes are below:
type
TMyData = record
Caption: string;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
RootNode: PVirtualNode;
PData: ^TMyData;
begin
RootNode := tvItems.AddChild(nil);
PData := tvItems.GetNodeData(RootNode);
PData^.Caption := 'This is a test node';
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
tvItems.NodeDataSize := SizeOf(TMyData);
end;
procedure TForm1.tvItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
PData: ^TMyData;
begin
if Assigned(Node) then
begin
PData := tvItems.GetNodeData(Node);
if Assigned(PData) then
Celltext := PData^.Caption;
end;
end;
When I click the "Button1", the root node will be created. However, when my mouse clicks the node text, it will not be selected.
Some of my findings:
One must clicks to the beginning of the node text to select the node. If clicking in middle or in the end of the node text, then the node will not be selected.
If I change tvItemsGetText to below, then the problem disappears:
procedure TForm1.tvItemsGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
PData: ^TMyData;
begin
CellText := 'This is a test node';
end;
I set a breakpoint in tvItemsGetText and find it will be invoked several times. At the first several times, the PData will be nil, which makes the CellText empty. At the final invokation, the PData will become valid and the CellText will be set to 'This is a test node'.
It seems that the range that allow mouse click and select the node is determined by the initial texts of the node. If the initial text is empty string, then one must click at the very beginning of the node to select it.
Is this a bug of Virtual Tree View?
There are several ways to init new node by user data.
1. Using OnInitNode event:
procedure TForm5.Button1Click(Sender: TObject);
begin
vt1.InsertNode(nil, amAddChildLast); // internal calls vt1InitNode
end;
procedure TForm5.vt1InitNode(Sender: TBaseVirtualTree; ParentNode, Node: PVirtualNode;
var InitialStates: TVirtualNodeInitStates);
var
PData: ^TMyData;
begin
PData := Sender.GetNodeData(Node);
PData^.Caption := 'This is a test node';
end;
2 Using UserData param
Variant 1. Dynamic data
Do not forget to remove InitNode event and dont set NodeDataSize property
type
TMyData = record
Caption: string;
end;
PMyData = ^TMyData;
procedure TForm5.Button1Click(Sender: TObject);
var
p: PMyData;
begin
New(p);
p.Caption:='This is a test node';
vt1.InsertNode(nil, amAddChildLast, p); // create node with initialized user data
// by default VirtualTree use NodeDataSize = SizeOf(pointer),
// so there is no reason to use GetNodeDataSize event
end;
procedure TForm5.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
PData: PMyData;
begin
if Assigned(Node) then
begin
PData := PMyData(Sender.GetNodeData(Node)^); // little modification
// for correct access to dynamic node data
if Assigned(PData) then
CellText := PData.Caption;
end;
end;
procedure TForm5.vt1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
p: PMyData;
begin
p:=PMyData(Sender.GetNodeData(Node)^);
Dispose(p); // as you allocate memory for user data - you should free it to avoid memory leaks
end;
Variant 2. Objects
Add new private function to your form:
private
{ Private declarations }
function GetObjectByNode<T: class>(Node: PVirtualNode): T;
// do not forget to include System.Generics.Collections to `uses`
realization:
function TForm5.GetObjectByNode<T>(Node: PVirtualNode): T;
var
NodeData: Pointer;
tmpObject: TObject;
begin
Result := nil;
if not Assigned(Node) then
exit;
NodeData := vt1.GetNodeData(Node);
if Assigned(NodeData) then
tmpObject := TObject(NodeData^);
if tmpObject is T then
Result := T(tmpObject)
else
Result := nil;
end;
And the main code (almost identical to variant 1):
procedure TForm5.Button1Click(Sender: TObject);
var
d: TMyData;
begin
d := TMyData.Create;
d.Caption := 'This is a test node';
vt1.InsertNode(nil, amAddChildLast, d);
end;
procedure TForm5.vt1FreeNode(Sender: TBaseVirtualTree; Node: PVirtualNode);
var
d: TMyData;
begin
d := GetObjectByNode<TMyData>(Node);
d.Free;
end;
procedure TForm5.vt1GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
d: TMyData;
begin
d := GetObjectByNode<TMyData>(Node);
if Assigned(d) then
CellText := d.Caption;
end;
Related
I followed the conventional practice of displaying data on TVirtualStringTree. But it displays only the string "node" in each cell. Can someone tell what I am missing here ?
Thanks in advance.
My Code:
type
TRecFileDirectory = record
FileDirectory: WideString;
FileDirectoryLock: wordbool;
end;
TPRecFileDirectory = ^TRecFileDirectory;
implementation
procedure TForm2.btn4Click(Sender: TObject);
var
I: Integer;
NewNode: PVirtualNode;
ptrFileDir: TPRecFileDirectory;
begin
vsTree1.BeginUpdate;
for I := 0 to Length(arrFileDirectory)-1 do
begin
NewNode := vsTree1.AddChild(nil);
ptrFileDir := vsTree1.GetNodeData(NewNode);
ptrFileDir^.FileDirectory := arrFileDirectory[I].FileDirectory;
ptrFileDir^.FileDirectoryLock := arrFileDirectory[I].FileDirectoryLock;
end;
vsTree1.EndUpdate;
btn4.caption := btn4.caption+' DONE';
end;
You need to implement an event handler for the OnGetText event, that extracts the string to be displayed from your data, dependant on the column and node that is supplied. For example:
procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
MyData: TPRecFileDirectory;
begin
MyData := Node.GetData();
if Column = 0 then
CellText := MyData.FileDirectory;
end;
Set DefaultText property to empty string, e.g. in code or in Inspector
How to copy all columns between two VirtualTreeView? In my case only the first one is copied.
I use VirtualTreeView v6.6.
The code that I'm using:
type
PItemNode1 = ^TItemNode1;
TItemNode1 = record
Name: WideString;
Order: string;
Quantity:String;
end;
type
PItemNode2 = ^TItemNode2;
TItemNode2 = record
Name: WideString;
Order: string;
end;
procedure TForm1.FormCreate(Sender: TObject);
var
Node: PVirtualNode;
begin
VT.NodeDataSize := SizeOf(TItemNode1);
VT2.NodeDataSize := SizeOf(TItemNode2);
VT.RootNodeCount := 2;
VT2.RootNodeCount := 10;
end;
Procedure for inserting OLE data
procedure TForm1.InsertData(Sender: TVirtualStringTree; DataObject: IDataObject;
Formats: TFormatArray; Effect: Integer; Mode: TVTNodeAttachMode);
var
FormatAccepted: Boolean;
i: Integer;
begin
FormatAccepted := false;
for i := 0 to High(Formats) do
begin
if Formats[i] = CF_VIRTUALTREE then
begin
if not FormatAccepted then
begin
Sender.ProcessDrop(DataObject, Sender.DropTargetNode, Effect, Mode);
FormatAccepted := True;
end;
end;
end;
end;
Drag and Drop precedures
procedure TForm1.VT2DragAllowed(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; var Allowed: Boolean);
begin
Allowed := True;
end;
procedure TForm1.VT2DragDrop(Sender: TBaseVirtualTree; Source: TObject;
DataObject: IDataObject; Formats: TFormatArray; Shift: TShiftState;
Pt: TPoint; var Effect: Integer; Mode: TDropMode);
procedure DetermineEffect;
begin
if Shift = [] then
begin
if Source = Sender then
Effect := DROPEFFECT_MOVE
else
Effect := DROPEFFECT_COPY;
end
else
begin
if (Shift = [ssAlt]) or (Shift = [ssCtrl, ssAlt]) then
Effect := DROPEFFECT_LINK
else if Shift = [ssCtrl] then
Effect := DROPEFFECT_COPY
else
end;
end;
var
Attachmode: TVTNodeAttachMode;
Nodes: TNodeArray;
i: Integer;
begin
Nodes := nil;
case Mode of
dmAbove:
Attachmode := amInsertBefore;
dmOnNode:
Attachmode := amAddChildLast;
dmBelow:
Attachmode := amInsertAfter;
else
Attachmode := amNowhere;
end;
if DataObject = nil then
begin
//VCL
if Source is TVirtualStringTree then
begin
DetermineEffect;
Nodes := VT2.GetSortedSelection(True);
if Effect = DROPEFFECT_COPY then
begin
for i := 0 to High(Nodes) do
VT2.CopyTo(Nodes[i], Sender.DropTargetNode, Attachmode, false);
end
else
for i := 0 to High(Nodes) do
VT2.MoveTo(Nodes[i], Sender.DropTargetNode, Attachmode, false);
end;
end
else
begin
// OLE drag&drop.
if Source is TBaseVirtualTree then
DetermineEffect
else
begin
if Boolean(Effect and DROPEFFECT_COPY) then
Effect := DROPEFFECT_COPY
else
Effect := DROPEFFECT_MOVE;
end;
InsertData(Sender as TVirtualStringTree, DataObject, Formats, Effect,
Attachmode);
end;
end;
procedure TForm1.VT2DragOver(Sender: TBaseVirtualTree; Source: TObject;
Shift: TShiftState; State: TDragState; Pt: TPoint; Mode: TDropMode;
var Effect: Integer; var Accept: Boolean);
// Return True, if AParent - child node of ANode.
function IsNodeParent(AParent, ANode: PVirtualNode): Boolean;
var
NextParent: PVirtualNode;
begin
NextParent := AParent;
repeat
NextParent := NextParent.Parent;
until (NextParent = Sender.RootNode) or (NextParent = nil) or
(NextParent = ANode);
Result := ANode = NextParent;
end;
var
i: Integer;
Nodes: TNodeArray;
begin
Accept := True;
if (Assigned(Sender.DropTargetNode)) and
(Sender.DropTargetNode <> Sender.RootNode) then
Nodes := (Sender as TVirtualStringTree).GetSortedSelection(True);
if Length(Nodes) > 0 then
begin
for i := 0 to Length(Nodes) - 1 do
begin
Accept :=
(not IsNodeParent(Sender.DropTargetNode, Nodes[i]))
and (not(Sender.DropTargetNode = Nodes[i]));
if not Accept then Exit;
end;
end;
end;
Initialize the nodes of VT2(right VT in the picture above )and get the text for them
procedure TForm1.VT2GetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
ItemNode: PItemNode2;
begin
ItemNode := Sender.GetNodeData(Node);
if Assigned(ItemNode) then
begin
case Column of
0:
CellText := ItemNode^.Name;
1:
CellText := ItemNode^.Order;
end;
end;
end;
procedure TForm1.VT2InitNode(Sender: TBaseVirtualTree;
ParentNode, Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
ItemNode: PItemNode2;
begin
ItemNode := Sender.GetNodeData(Node);
if Assigned(ItemNode) then
if Length(ItemNode^.Name) = 0 then
ItemNode^.Name := 'Node Index № ' + IntToStr(Node.Index);
ItemNode^.Order := IntToStr(Node.Index);
end;
Get a new text after the node is dropped
procedure TForm1.VT2NewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; NewText: string);
var
ItemNode: PItemNode2;
begin
ItemNode := Sender.GetNodeData(Node);
if Assigned(ItemNode) then
begin
case Column of
0:
ItemNode^.Name := NewText;
1:
ItemNode^.Order := NewText; // I've checked this line in the debugger. It is skipped
end;
end;
end;
Initialize the nodes of VT(left VT in the picture above )and get the text for them
procedure TForm1.VTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
var
ItemNode: PItemNode1;
begin
ItemNode := Sender.GetNodeData(Node);
if Assigned(ItemNode) then
case Column of
0:
CellText := ItemNode^.Name;
1:
CellText := ItemNode^.Order;
end;
end;
procedure TForm1.VTInitNode(Sender: TBaseVirtualTree; ParentNode,
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
var
ItemNode: PItemNode1;
begin
ItemNode := Sender.GetNodeData(Node);
if Assigned(ItemNode) then
if Length(ItemNode^.Name) = 0 then
ItemNode^.Name := 'VT1_Node № ' + IntToStr(Node.Index);
ItemNode^.Order := IntToStr(Node.Index);
end;
end.
I use Delphi XE5 and created a VirtualTree with several parent and child nodes. When I select a child node and execute the following code:
vstSource:= vstTree.FocusedNode;
vstTarget:= vstTree.GetNextSibling(vstSource);
vstTree.moveto(vstSource,vstTarget,amInsertAfter,false);
The cursor jumps to the next node and selects it but the selected node does not move down.
I use VirtualTreeView v.5.3.0.
Can anybody tell me what's wrong?
Edit:
I've made an update to v.6.0 but nothing changes. Here's the full code (it's only a sample to test the VirtualTree):
procedure TForm1.Button1Click(Sender: TObject);
begin
myTree.RootNodeCount := 2;
end;
procedure TForm1.Button2Click(Sender: TObject);
var
SNode, TNode: PVirtualNode;
begin
SNode:= myTree.FocusedNode;
TNode:= myTree.GetNextSibling(SNode);
myTree.MoveTo(SNode, TNode, amInsertAfter, False);
end;
procedure TForm1.myTreeGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; TextType: TVSTTextType; var CellText: string);
begin
if Column > 0 then
Exit;
case Sender.GetNodeLevel(Node) of
0: CellText := 'Main';
1:
case Node.Index of
0: CellText := 'Val1';
1: CellText := 'Val2';
2: CellText := 'Val3';
3: CellText := 'Val4';
4: CellText := 'Val5';
end;
end;
end;
procedure TForm1.myTreeInitNode(Sender: TBaseVirtualTree; ParentNode,
Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);
begin
if Sender.GetNodeLevel(Node) = 0 then
Sender.ChildCount[Node] := 5;
end;
In short, I'm trying to add Object into VirtualTreeView but am always getting error EAccessViolation at CellText I'm wondering about the reason for the error i tried to do my best but without result...
this is my attempt:
TForm1 = class(TForm)
private
public
end;
TPerson = class;
PPersonNode = ^TPersonNode;
TPersonNode = record
PersonObj: TPerson;
end;
TPerson = class(TObject)
private
FName: string;
public
property Name: string read FName write FName;
end;
procedure TForm1.Button1Click(Sender: TObject);
var
PersonRec: PPersonNode;
begin
PersonRec := VirtualStringTree1.GetNodeData(VirtualStringTree1.AddChild(nil));
PersonRec.PersonObj := TPerson.Create;
PersonRec.PersonObj.Name := 'aaa';
end;
procedure TForm1.VirtualStringTree1GetNodeDataSize(Sender: TBaseVirtualTree;
var NodeDataSize: Integer);
begin
NodeDataSize := SizeOf(TPersonNode);
end;
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
PersonRec: PPersonNode;
begin
PersonRec := Sender.GetNodeData(Node);
CellText := PersonRec.PersonObj.Name;
end;
It looks like the OnGetText event is being fired before the TPerson object has been created. Try checking that the object isn't nil first:
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
PersonRec: PPersonNode;
begin
PersonRec := Sender.GetNodeData(Node);
if PersonRec <> nil then // <- check that the object has been created
CellText := PersonRec.PersonObj.Name;
end;
I would change this:
procedure TForm1.Button1Click(Sender: TObject);
var
PersonRec: PPersonNode;
begin
PersonRec := VirtualStringTree1.GetNodeData(VirtualStringTree1.AddChild(VirtualStringTree1.RootNode));
PersonRec.PersonObj := TPerson.Create;
PersonRec.PersonObj.Name := 'aaa';
end;
and this:
procedure TForm1.VirtualStringTree1GetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
PersonRec: PPersonNode;
begin
if Assigned(Node) then
begin
PersonRec := Sender.GetNodeData(Node);
CellText := PersonRec.PersonObj.Name;
end;
end;
How do I do create a listview (or similar) with a button on each line? The button needs to be able to have different text/color on each line as required.
I'm sure Virtual Treeview would be perfect for this, but I'm a little lost with it.
Thanks
-Brad
With a virtualtreeview...... add vstButton to your uses and select your Virtualtreeview in the object inspector and set the following events for your tree:
procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; out EditLink: IVTEditLink);
begin
EditLink:=TStringEditLink.Create;
end;
procedure TForm1.FormCreate(Sender: TObject);
begin
VST.NodeDataSize := SizeOf(TTreeData);
AddRandomNodesToTree(Vst);
end;
procedure TForm1.VSTFreeNode(Sender: TBaseVirtualTree;
Node: PVirtualNode);
var
Data: PTreeData;
begin
Data:=VST.GetNodeData(Node);
if Assigned(Data) then begin
Data^.Column0 := '';
Data^.Column1 := '';
Data^.Column2 := '';
end;
end;
procedure TForm1.VSTGetText(Sender: TBaseVirtualTree;
Node: PVirtualNode; Column: TColumnIndex; TextType: TVSTTextType;
var CellText: string);
var
Data: PTreeData;
begin
Data := VST.GetNodeData(Node);
case Column of
0: CellText := Data^.Column0;
1: CellText := Data^.Column1;
2: CellText := Data^.Column2;
end;
end;
procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;
Column: TColumnIndex; NewText: string);
Var
Data: PTreeData;
begin
Data := VST.GetNodeData(Node);
Case Column of
0: Data^.Column0:= NewText;
1: Data^.Column1:= NewText;
2: Data^.Column2:= NewText;
End;
end;
procedure TForm1.VSTPaintText(Sender: TBaseVirtualTree;
const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
TextType: TVSTTextType);
Var
Data: PTreeData;
begin
if Odd(Node.Index) then
TargetCanvas.Font.Color:= clRed;
end;
... this assumes the record is:
type
PTreeData = ^TTreeData;
TTreeData = record
Column0: String;
Column1: String;
Column2: String;
end;
...add the following unit:
unit vstButton;
interface
uses
Classes, SysUtils, Forms, Controls, Graphics, Dialogs, VirtualTrees,
messages, windows, StdCtrls, ShlObj;
type
TStringEditLink = class(TInterfacedObject, IVTEditLink)
private
FEdit: TWinControl;
FTree: TVirtualStringTree;
FNode: PVirtualNode;
FColumn: Integer;
FSelectedFolder: string;
protected
procedure ButtonClick(Sender: TObject);
public
destructor Destroy; override;
function BeginEdit: Boolean; stdcall;
function CancelEdit: Boolean; stdcall;
function EndEdit: Boolean; stdcall;
function GetBounds: TRect; stdcall;
function PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean; stdcall;
procedure ProcessMessage(var Message: TMessage); stdcall;
procedure SetBounds(R: TRect); stdcall;
end;
function GetFolderDialog(Handle: Integer; Caption: string; var strFolder: string): Boolean;
implementation
destructor TStringEditLink.Destroy;
begin
FEdit.Free;
inherited;
end;
procedure TStringEditLink.ButtonClick(Sender: TObject);
var
s: string;
begin
s := 'c:\';
if GetFolderDialog(Application.Handle, 'Select a folder', s) then
FSelectedFolder := s;
FTree.EndEditNode;
FTree.setfocus;
end;
function TStringEditLink.BeginEdit: Boolean;
begin
Result := True;
FSelectedFolder := FTree.Text[FNode, FColumn];
TButton(FEdit).CAption := FTree.Text[FNode, FColumn];
FEdit.Show;
FEdit.SetFocus;
end;
function TStringEditLink.CancelEdit: Boolean;
begin
Result := True;
FEdit.Hide;
FTree.EndEditNode;
FTree.setfocus;
end;
function TStringEditLink.EndEdit: Boolean;
var
S: WideString;
begin
Result := True;
FTree.Text[FNode, FColumn] := FSelectedFolder;
FTree.InvalidateNode(FNode);
FEdit.Hide;
FTree.SetFocus;
end;
function TStringEditLink.GetBounds: TRect;
begin
Result := FEdit.BoundsRect;
end;
function TStringEditLink.PrepareEdit(Tree: TBaseVirtualTree; Node: PVirtualNode; Column: TColumnIndex): Boolean;
begin
Result := True;
FTree := Tree as TVirtualStringTree;
FNode := Node;
FColumn := Column;
FEdit.Free;
FEdit := nil;
FEdit := TButton.Create(nil);
with FEdit as TButton do
begin
Visible := False;
Parent := Tree;
Font.Color := FTree.Colors.HeaderHotColor;
OnClick := ButtonClick;
end;
end;
procedure TStringEditLink.ProcessMessage(var Message: TMessage);
begin
FEdit.WindowProc(Message);
end;
procedure TStringEditLink.SetBounds(R: TRect);
var
Dummy: Integer;
begin
FTree.Header.Columns.GetColumnBounds(FColumn, Dummy, R.Right);
FEdit.BoundsRect := R;
end;
//------------------------------------------------------------------------------\\
function BrowseCallbackProc(hwnd: HWND; uMsg: UINT; lParam: LPARAM; lpData: LPARAM): Integer; stdcall;
begin
if (uMsg = BFFM_INITIALIZED) then
SendMessage(hwnd, BFFM_SETSELECTION, 1, lpData);
BrowseCallbackProc := 0;
end;
function GetFolderDialog(Handle: Integer; Caption: string; var strFolder: string): Boolean;
const
BIF_STATUSTEXT = $0004;
BIF_NEWDIALOGSTYLE = $0040;
BIF_RETURNONLYFSDIRS = $0080;
BIF_SHAREABLE = $0100;
BIF_USENEWUI = BIF_EDITBOX or BIF_NEWDIALOGSTYLE;
var
BrowseInfo: TBrowseInfo;
ItemIDList: PItemIDList;
JtemIDList: PItemIDList;
Path: PChar;
begin
Result := False;
Path := StrAlloc(MAX_PATH);
SHGetSpecialFolderLocation(Handle, CSIDL_DRIVES, JtemIDList);
with BrowseInfo do
begin
hwndOwner := GetActiveWindow;
pidlRoot := JtemIDList;
SHGetSpecialFolderLocation(hwndOwner, CSIDL_DRIVES, JtemIDList);
{ return display name of item selected }
pszDisplayName := StrAlloc(MAX_PATH);
{ set the title of dialog }
lpszTitle := PChar(Caption);//'Select the folder';
{ flags that control the return stuff }
lpfn := #BrowseCallbackProc;
{ extra info that's passed back in callbacks }
lParam := LongInt(PChar(strFolder));
end;
ItemIDList := SHBrowseForFolder(BrowseInfo);
if (ItemIDList <> nil) then
if SHGetPathFromIDList(ItemIDList, Path) then
begin
strFolder := Path;
Result := True
end;
end;
End.
the above code is based upon code found at this website:
http://wiki.freepascal.org/VirtualTreeview_Example_for_Lazarus
If you look at the unit vstButton, to get a TEdit, or TCombo...etc... just replace any TButton reference with TEdit or TCombo etc... adjust events for it etc... The above link code actually uses a TCombo
that website helped me alot to learn how to use the virtualtreeview
the above code will insert a Tbutton into every cell, and when you click on the button it will open a BrowseForFolder dialog and insert the result back into the virtualtreeview cell
Hope this helps
did you want a button visible in a cell column all the time? Could simulate the button with an image... like a dropdown mark on one side of the cell