VirtualTreeview Example for Lazarus/es

From Lazarus wiki
Jump to navigationJump to search

English (en) español (es) français (fr) polski (pl) русский (ru)

Aqui hay algunos ejemplos acerca de como how usar el control VirtualTreeview para Lazarus (probado en win32). La mayoria de estos ejemplos han sido recolectados de la web, escritos para delphi, y de los documentos o tutoriales por Philipp Frenzel y Mike Lischke. Los documentos o tutoriales pueden ser descargados desde http://www.soft-gems.net . Abajo, usted puede encontrar alguna forma rapida de como utilizar VirtualTreeview en Lazarus, no explicaciones detallas. Para mas explicaciones y otros metodos o funciones, obtenga los documentos oficiales y el tutorial.

Ejemplo Tree Listview basico con 3 columnas

1. Instalar el componente. Ejecutar Lazarus.

2. Arrastre un componente TVirtualStringTree (bajo la pagina Controles Visuales).

3. Vaya al editor de codigo (oprima la tecla F12). Bajo la sentencia Uses agregue una unidad - escriba VirtualTrees (si no existe previamente, no confunda con la unidad VirtualStringTree). Se vera de forma igual o similar a : <delphi>uses

 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
 VirtualStringTree, VirtualTrees;</delphi>  

4. Vaya al Diseñador de Formas (oprima la tecla F12). Seleccione el componente Virtual Tree. En el Inspector de Objetos haga clic en Nombre, escriba VST y oprima la tecla Enter (Return). Haga clic en Encabezado (expandalo) -> Columnas, haga clic en el pequeño boton, al lado de "0 elementos". Haga clic 3 veces en agregar boton para agregar 3 columnas. No cierre esta ventana.

5. En la ventana para Edicion de Columna, aparecera la 3ra. columna como seleccionada. Vaya al Inspector de Objetos. Haga clic en Opciones (expandalo) -> y asigne coAllowClick como False.

6. Haga clic en Texto. Escriba Column2.

7. Haga clic en ancho, escriba 100 y oprima la tecla Enter (Return).

8. Vaya a la ventana para Edicion de Columna, seleccione las columnas 1ra. y 2da., y asigne su propiedad como la de arriba (para el campo Texto, use nombres diferentes, ejemplo: Columna0, Columna1).

9. Cierre la ventana para Edicion de Columna. Seleccione el component Virtual Tree en la forma. En el Inspector de Objetos vaya a Encabezado -> Opciones (expandalo). Asigne coAllowClick como True.

10. Desplazece hacia abajo hasta Style, y asignelo como hsFlatButtons.

11. Desplazece hacia abajo hasta TreeOptions (expandalo) -> MiscOption (expandalo), y asigne toEditable como True. Asigne toGridExtensions como True.

12. Desplazece hacia abajo hasta SelectionOptions (expandalo) -> y asigne toExtendedFocus como True. Asigne toMultiSelect como True. En el Diseñador de Formas cambie el tamaño del VST (componente Virtual) para para poder visualizar todas las columnas, en caso de que sea necesario.

13. Ahora, para agregar 3 botones en la forma. Arrastrelos desde la paleta de componentes - Pagina Estandar (Etiquetados como "OK").

14. Haga clic en Button1, en el Inspector de Objetos cambie Titulo a "AddRoot". Haga clic en el Button2, cambie el titulo a "AddChild". Cambie el titulo de Button3 a "Delete".

15. Mantenga esto aqui y vaya al editor de codigo (oprima la tecla F12). En el Editor de Codigo reemplace la linea:

{$mode objfpc}{$H+} with {$MODE DELPHI}

16. Bajo la sentencia "implementation" pegue las siguientes lineas de codigo:

<delphi>type

 PTreeData = ^TTreeData;
 TTreeData = record
   Column0: String;
   Column1: String;
   Column2: String;
 end;</delphi>

17. Vaya al Diseñador de Formas (oprima la tecla F12). Seleccione el control VST. Vaya al Inspector de Objetos, seleccione la pagina Eventos, desplazece hasta el evento onChange. Haga doble clic en el control combobox.

18. Desplazece hasta el evento onFocusChanged. Haga doble clic y pegue el codigo siguiente: <delphi>procedure TForm1.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Column: TColumnIndex);

begin

 VST.Refresh;

end;</delphi>

19. Desplazece hasta el evento onFreeNode. Haga doble clic y pegue el codigo siguiente: <delphi>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;</delphi>

20. Desplazece hasta el evento onGetNodeDataSize. Haga doble clic y pegue el codigo siguiente: <delphi>procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer); begin

 NodeDataSize := SizeOf(TTreeData);

end;</delphi>

21. Desplazece hasta el evento onGetText. Haga doble clic y pegue el codigo siguiente: <delphi>procedure TForm1.VSTGetText(Sender: TBaseVirtualTree; Node: PVirtualNode;

Column: TColumnIndex; TextType: TVSTTextType; var CellText: WideString);

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;</delphi>

22. Oprima la tecla F12 para ir al Diseñador de Formas. Haga doble clic en el boton "AddRoot". Haga doble clic y pegue el codigo siguiente:

<delphi>procedure TForm1.Button1Click(Sender: TObject); Var

 Data: PTreeData;
 XNode: PVirtualNode;
 Rand: Integer;

Begin

 Randomize;
 Rand := Random(99);
 XNode:=VST.AddChild(nil);
 
 if VST.AbsoluteIndex(XNode) > -1 then
 Begin
  Data := VST.GetNodeData(Xnode);
  Data^.Column0:= 'One ' + IntToStr(Rand);
  Data^.Column1:= 'Two ' + IntToStr(Rand + 10);
  Data^.Column2:= 'Three ' + IntToStr(Rand - 10);
 End; 

End;</delphi>

23. Oprima la tecla F9 para Ejecutar el proyecto y revisarlo. Haga clic en el boton "AddRoot" para agregar un nodo. SI no hay problema alguno, el nodo sera agregado al control VST.

24. Detenga la ejecucion del programa. En el Diseñador de Formas haga doble clic en el boton titulado "AddChild". Haga doble clic y pegue el codigo siguiente:

<delphi>procedure TForm1.Button2Click(Sender: TObject); var

 XNode: PVirtualNode;
 Data: PTreeData;

begin

 if not Assigned(VST.FocusedNode) then
   Exit;
   
   XNode := VST.AddChild(VST.FocusedNode);
   Data := VST.GetNodeData(Xnode);
   
   Data^.Column0:= 'Ch 1';
   Data^.Column1:= 'Ch 2';
   Data^.Column2:= 'Ch 3';
  VST.Expanded[VST.FocusedNode]:=True;

end;</delphi>

25. En el Diseñador de Formas haga doble clic en el boton titulado "Delete". Haga doble clic y pegue el codigo siguiente:

<delphi>procedure TForm1.Button3Click(Sender: TObject); begin

 VST.DeleteSelectedNodes;

end;</delphi>

26. Ejecute el proyecto, oprimiendo la tecla F9 para revisarlo. Haga varias pruebas, agregando algunos nodos principales, nodos hijos y eliminelos.

27. Intente editar un node. Seleccione un nodo y oprima la tecla F2, y escriba un nuevo valor. Si puede ver lo que esta escribiendo, entonces, el paso esta bien. De lo contrario, lea la seccion siguiente titulada "Cuando la edicion de celda no puede verse".

28. Para obtener que el V.S.T. muestre el nuevo valor capturado despues de la edicion, vaya al Diseñador de Formas, y seleccione V.S.T. Haga doble clic, en la cajacombo de el Inspector de Objetos -> Events -> OnNewText. Haga doble clic y pegue el codigo siguiente:

<delphi>procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Column: TColumnIndex; NewText: WideString);

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;</delphi>

Hasta ahora, el ejemplo para uso basico, termina aqui. Usted podria arrastrar algunos botones adicionales en la forma para probar algunos de los comandos mencionados, mas adelante. El paso siguiente, podria ser, desplegar una casill para marcar o "checkbox", imagen, color para tipo de fuente de texto, o agregar una cajacombo al nodo.

  • Otra forma para agregar el nodo raiz:

<delphi>procedure TForm1.Button8Click(Sender: TObject); begin

 with VST do
 RootNodeCount:=RootNodeCount+1;

end;</delphi>

  • Otra forma para agregar un nodo hijo:

<delphi>procedure TForm1.Button9Click(Sender: TObject); begin

 if Assigned(VST.FocusedNode) Then
 VST.ChildCount[VST.FocusedNode]:=VST.ChildCount[VST.FocusedNode]+1;

end;</delphi>

  • Determinar y eliminar los nodos hijos de un nodo:

<delphi>procedure TForm1.Button4Click(Sender: TObject); Var

 c: Integer;

begin

 if not Assigned(VST.FocusedNode) then
   Exit;
 If VST.HasChildren[VST.FocusedNode] then
 Begin
   c := VST.ChildCount[VST.FocusedNode];
   VST.DeleteChildren(VST.FocusedNode);
   ShowMessage('Number of deleted child:' + #13#10 + IntToStr(c));
 End;

end;</delphi>

  • Eliminar un nodo:

<delphi>procedure TForm1.Button5Click(Sender: TObject); begin {VST.Clear; //Delete All Nodes}

 if not Assigned(VST.FocusedNode) then
   Exit;
 VST.DeleteNode(VST.FocusedNode);

end;</delphi>

  • Buscar y seleccionar un nodo:

<delphi>procedure TForm1.Button6Click(Sender: TObject); bar

 XNode: PVirtualNode;
 Data: PTreeData;

begin

 XNode:= VST.GetFirst;
 while XNode <> nil do
 begin
   Data:=VST.GetNodeData(XNode);
   if Data^.Column0  = '1' then
   begin
     VST.ClearSelection;
     VST.Selected[XNode]:=True;
     VST.SetFocus;
     break;
   end else
   XNode:= VST.GetNextSibling(XNode);
 end;

end;</delphi>

  • Determinar el nodo padre de un nodo:

<delphi>procedure TForm1.Button13Click(Sender: TObject); var

 XNode: PVirtualNode;

begin

 if not Assigned(VST.FocusedNode) then
   Exit;
 XNode:=VST.FocusedNode;
 while VST.GetNodeLevel(XNode) > 0 do
   Begin
   XNode := XNode.Parent;
   VST.Selected[XNode]:= True;
   End;
  VST.Refresh;
  VST.SetFocus;

end;</delphi>

  • Buscar todos los nodos:

<delphi>procedure TForm1.Button7Click(Sender: TObject); Var

 XNode: PVirtualNode;
 Data: PTreeData;

begin

 If VST.GetFirst = nil then Exit;
 XNode:=nil;
 Repeat
   if XNode = nil then XNode:=VST.GetFirst Else XNode:=VST.GetNext(XNode);
   Data:=VST.GetNodeData(XNode);
   If (Data^.Column0 = '1') OR (Data^.Column1 = '1') OR (Data^.Column2 = '1') then
   Begin
     ShowMessage('Found at Node Level : ' + IntToStr(VST.GetNodeLevel(XNode)) );
     break;
   End;
 Until XNode = VST.GetLast();

end;</delphi>

  • Buscar el nodo siguiente:

<delphi>procedure TForm1.Button8Click(Sender: TObject); var

 XNode: PVirtualNode;
 Data: PTreeData;

begin

 if not Assigned(VST.GetFirst) then
   Exit
 else
   XNode := VST.GetFirst;
 repeat
   XNode := VST.GetNext(XNode);
   Data := VST.GetNodeData(XNode);
   if Pos(LowerCase(SearchEdit.Text), LowerCase(Data^.Column0)) > 0 then
   begin
     VST.FocusedNode := XNode;
     VST.Selected[XNode] := True;
     if MessageDlg('Item found?', mtConfirmation, mbYesNo, 0) = mrYes then
     begin
       VST.Expanded[XNode] := True;
       VST.Refresh;
       VST.SetFocus;
       Break;
     end;
   end;
 until XNode = VST.GetLast;

end;</delphi>

  • Insertar Nodo:

<delphi>procedure TForm1.Button12Click(Sender: TObject); var

 XNode: PVirtualNode;

begin

 If Assigned(VST.FocusedNode) then
 begin
    XNode := VST.InsertNode(VST.FocusedNode,amInsertBefore);
    // To Insert After Selected Node.
    {XNode := VST.InsertNode(VST.FocusedNode,amInsertAfter);}
    VST.Refresh;
 end;

end;</delphi>

  • Asignar la altura de un nodo:

<delphi>procedure TForm1.Button14Click(Sender: TObject); begin

  If Assigned(VST.FocusedNode) then
  VST.NodeHeight[VST.FocusedNode] := 32;

end;</delphi>

  • Guardar y Cargar:

El arbol simple (sin columnas), puede ser guardado y recargado con:

<delphi> VST.SaveToFile('filename.dat'); VST.LoadFromFile('filename.dat'); </delphi>

Para guardar y cargar el ejemplo mencionado arriba, coloque 2 botones en la forma, cambie el titulo de un boton a "Guardar", y el titulo del otro boton a "Cargar". Seleccione el V.S.T., En el Inspector de Objetos -> TreeOptions -> StringOptions. Asegurese, que el valor de la propiedad toSaveCaptions este asignada como True. Vaya a la pagina del Inspector de Eventos Events. Desplazece hasta OnLoadNode, haga doble cilc y pegue el codigo siguiente:

<delphi>procedure TForm1.VSTLoadNode(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Stream: TStream);

Var

 Data: PTreeData;
 Len: Integer;

begin

 Data := VST.GetNodeData(Node);
 Stream.read(Len, SizeOf(Len));
 SetLength(Data^.Column0, Len);
 Stream.read(PChar(Data^.Column0)^, Len);
 Stream.read(Len, SizeOf(Len));
 SetLength(Data^.Column1, Len);
 Stream.read(PChar(Data^.Column1)^, Len);
 Stream.read(Len, SizeOf(Len));
 SetLength(Data^.Column2, Len);
 Stream.read(PChar(Data^.Column2)^, Len);

end;</delphi>

Otra vez, en la pagina Events del Inspector de Objetos, desplazece hasta OnSaveNode, haga doble cilc y pegue el codigo siguiente:

<delphi> procedure TForm1.VSTSaveNode(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Stream: TStream);

Var

 Data: PTreeData;
 Len: Integer;

begin

 Data := VST.GetNodeData(Node);
 Len := Length(Data^.Column0);
 Stream.write(Len, SizeOf(Len));
 Stream.write(PChar(Data^.Column0)^, Len);
 Len := Length(Data^.Column1);
 Stream.write(Len, SizeOf(Len));
 Stream.write(PChar(Data^.Column1)^, Len);
 Len := Length(Data^.Column2);
 Stream.write(Len, SizeOf(Len));
 Stream.write(PChar(Data^.Column2)^, Len);

end;</delphi>

En el Diseñador de Formas, haga doble clic en el boton titulado "Save" o "Guargar", y pegue el codigo siguiente:

<delphi>procedure TForm1.Button10Click(Sender: TObject); begin

VST.SaveToFile('C:\vst.dat');

end;</delphi>

En el Diseñador de Formas, haga doble clic en el boton titulado "Load" o "Cargar", y pegue el codigo siguiente:

<delphi> procedure TForm1.Button11Click(Sender: TObject); begin

 VST.LoadFromFile('C:\vst.dat');

end; </delphi>

Ahora, haga pruebas, para guardar y volver a cargar el arbol.

  • Problema de desplazamiento

El encabezado de control vistaarbol desaparece parcialmente o completamente al desplazarse. No pude encontrar una buena solucion a esto. Una forma de sobrepasar esto, es asignar la altura del encabezado a 0, y utilizar una etiqueta generica para las columnas, y todas las columnas estan visibles sin desplazamiento horizontal. O, la altura del encabezado puede ser asignada un valor mas alto, entre 25 o 30. El metodo VST.Refresh puede ser asignado al evento OnScroll.

  • Cambiar el tamaño de las columnas

No fue posible cambiar el tamaño de las columnas, arrastrando el raton en el encabezado del V.S.T. Tal vez, sea debido al "bug" del encabezado, o tal vez, omiti algo. En caso de que la causa haya sido el encabezado, tal vez sea corregido en la siguiente version de Lazarus. Puede ver este enlace: http://bugs.freepascal.org/view.php?id=11209

De cualquier forma, es posible cambiar el tamaño de las columnas por medio de codigo. Cuando used When you press down right mouse button and move mouse-wheel up, the width of the selected column increases and press down the right mouse button and move mouse-wheel down, to decrease the width of the selected column. To do this:

1. Add a variable in the source editor named as CurCol: Integer; So it looks like: <delphi>var

 Form1: TForm1; 
 CurCol: Integer; // <- Add this line only.

implementation

{ TForm1 } </delphi>

2. On the Form Designer double click the form to generate an event OnCreate. Inside the OnCreate procedure type Form1.OnMouseWheelUp:= and press Ctrl+Shift+C, this will complete the code and make skeleton of the MouseWheelUp event. Now get back to procedure TForm1.FormCreate(Sender: TObject); And add another event for MouseWheelDown. Type Form1.OnMouseWheelDown:= and press Ctrl+Shift+C, to generate the MouseWheelDown event. FormCreate procedure now looks like: <delphi>procedure TForm1.FormCreate(Sender: TObject); begin

 Form1.OnMouseWheelUp:=@Form1MouseWheelUp;
 Form1.OnMouseWheelDown:=@Form1MouseWheelDown;

end;</delphi>

3. Fill the TForm1.Form1MouseWheelUp procedure as: <delphi>procedure TForm1.Form1MouseWheelUp(Sender: TObject; Shift: TShiftState;

 MousePos: TPoint; var Handled: Boolean);

begin

If VST.Focused then
  if ssRight in Shift then
VST.Header.Columns[CurCol].Width:= VST.Header.Columns[CurCol].Width + 10;

end;</delphi>

4. Fill the TForm1.Form1MouseWheelDown procedure as: <delphi>procedure TForm1.Form1MouseWheelDown(Sender: TObject; Shift: TShiftState;

 MousePos: TPoint; var Handled: Boolean);

begin

 If VST.Focused then
  if ssRight in Shift then
VST.Header.Columns[CurCol].Width:= VST.Header.Columns[CurCol].Width - 10;

end;</delphi>

5. Go to the Form Designer (press F12), select VST, on Object Inspector's Events tab scroll to OnFocusChanged, double click & paste: <delphi>procedure TForm1.VSTFocusChanged(Sender: TBaseVirtualTree;

 Node: PVirtualNode; Column: TColumnIndex);

begin

 CurCol:=Column;

end;</delphi>

Cuando ejecute el programa, haga clic en una columna, despues mantenga presionado abajo, el boton derecho del raton, y gire la rueda arriba, para incrementar el ancho. Gire la rueda abajo decrementar los valores mencionados. Podria modificar los procedimientos anteriores, para ajustar un poco el resultado, si es necesario. O, agregar algun evento para el teclado, con algo como "if (key=187) and (ssShift in Shift) then" para utilizar la combinacion de teclas Shift + "+".

Checkbox

On Form Designer select VST. Go to:

  1. Object Inspector -> Properties -> CheckImageKind and select ckDarkCheck.
  2. Object Inspector -> Properties -> TreeOptions -> MiscOptions -> toCheckSupport and set it to True.

Now switch to Events tab.

  • Scroll to OnInitNode. Double click and paste the followings:

<delphi>procedure TForm1.VSTInitNode(Sender: TBaseVirtualTree; ParentNode,

 Node: PVirtualNode; var InitialStates: TVirtualNodeInitStates);

Var

 Level: Integer;

begin

 Level := VST.GetNodeLevel(Node);
 if Level = 0 then
   Node.CheckType:=ctCheckBox;
 if Level = 2 then
   Node.CheckType:=ctRadioButton;
 if Level = 1 then
 begin
   Node.CheckType:=ctTriStateCheckBox;
   Node.CheckState := csCheckedNormal;
 end;
 if Level = 3 then
   Node.CheckType:=ctButton;

end;</delphi> Run the program, add rootnode and child then child of the child, and check if you can check and uncheck properly. If not, close the program. Go to the Object Inspector's Events tab.

  • Scroll to OnChecked, double click and paste:

<delphi>procedure TForm1.VSTChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); begin

  vst.Refresh;

end;</delphi>

  • Scroll to OnChecking, double click and paste:

<delphi>procedure TForm1.VSTChecking(Sender: TBaseVirtualTree; Node: PVirtualNode;

 var NewState: TCheckState; var Allowed: Boolean);

begin

VST.Refresh;

end;</delphi> Hope now it is ok. To determine checkbox state use like:

If XNode.CheckState = csCheckedNormal then
ShowMessage('Checked.');

Other states are:
<delphi>csUncheckedNormal = unchecked and not pressed csUncheckedPressed = unchecked and pressed csCheckedNormal = checked and not pressed csCheckedPressed = checked and pressed csMixedNormal = 3-state check box and not pressed csMixedPressed = 3-state check box and pressed</delphi>

Other types are:
<delphi>ctNone ctTriStateCheckBox ctCheckBox ctRadioButton ctButton</delphi>

  • To Catch Checkbox's Button (ctButton) Click

Go to Object Inspector's Events tab. Scroll to OnChecked, double click and paste: <delphi>procedure TForm1.VSTChecked(Sender: TBaseVirtualTree; Node: PVirtualNode); begin

if Node.CheckType = ctButton then
ShowMessage('Ok.');
VST.Refresh;

end;</delphi> End of checkbox.


Images

To show image on VST nodes, a list of image should be created.

  • Go to the Component Palette -> Common Controls. Select and drop a TImageList component on the form. Right click on the component icon and select ImageList Editor. Click on Add button and and select some images (at least 3 for now), then click on tick button to accept and close the ImageList Editor. By the way, there are some nice images you can download from http://www.famfamfam.com/lab/icons/silk/
  • Now on the Form Designer select VST, and on Object Inspector's Properties tab, scroll to Images and select ImageList1
  • On Object Inspector's Events tab scroll to OnGetImageIndex, double click and paste:

<delphi>procedure TForm1.VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean;
 var ImageIndex: Integer);

begin

 if Kind in [ikNormal , ikSelected] then // Either Selected or not
 begin
   if Column = 0 then                    // if 1st Column
     ImageIndex:=0;                      // 1st Image of the ImageList1
   if Column = 1 then                    // if 2nd Column
     ImageIndex:=1;                      // 2nd Image of the ImageList1
   if Sender.FocusedNode = Node then     // Only show if Focused
     if Column =2 then                    // if 3rd Column
       ImageIndex:=2;                      // 3rd Image of the ImageList1
 end;
 {Sender.NodeHeight[node]:=40; //If Image is big}

end;</delphi>

Font Colour

On the Form Designer select VST, and on Object Inspector's Events tab, scroll to OnPaintText, double click and paste: <delphi>procedure TForm1.VSTPaintText(Sender: TBaseVirtualTree;

 const TargetCanvas: TCanvas; Node: PVirtualNode; Column: TColumnIndex;
 TextType: TVSTTextType);

Var

 Data: PTreeData;

begin

 Data := VST.GetNodeData(Node);

 if Data^.Column0 = 'sky' then
   TargetCanvas.Font.Color:=clBlue;
 
 if Column = 1 then
 begin
   TargetCanvas.Font.Color:=clRed;
   TargetCanvas.Font.Style:= Font.Style + [fsItalic];
 end;

 if Column = 2 then
 begin

// ImageList1.Draw(Form1.Canvas,-1,-1,2); {draw top left of form, 3rd image of ImageList1??}

   TargetCanvas.Font.Size:= 9;
   TargetCanvas.Font.Color:=clHighlightText;
 end;

end;</delphi>

Adding A Combobox

  • I guess you have an open project on Lazarus IDE having VST on it and can edit the nodes. If not see the "Basic Tree Listview With 3 Columns" above, and atleast complete steps 1 to 21.
  • Bellow there is an unit file named combo. Copy that unit and save as combo.pas inside the project directory. Under your program's uses clause add combo. So it may look like:

<delphi>uses

 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
 VirtualStringTree, VirtualTrees, combo;</delphi>
  • The combo.pas unit

<delphi>unit combo;

{$mode delphi}

interface

uses

 Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
 VirtualStringTree, VirtualTrees, messages, windows, StdCtrls;

type

 TStringEditLink = class(TInterfacedObject, IVTEditLink)
 private
   FEdit: TWinControl;
   FTree: TVirtualStringTree;
   FNode: PVirtualNode;
   FColumn: Integer;
 protected
   procedure EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState);
 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;

implementation

destructor TStringEditLink.Destroy; begin

 FEdit.Free;
 inherited;

end;

procedure TStringEditLink.EditKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin

 case Key of
   VK_ESCAPE:
     begin
       FTree.CancelEditNode;
       Key := 0;
       FTree.setfocus;
     end;
   VK_RETURN:
     begin
      PostMessage(FTree.Handle, WM_KEYDOWN, VK_DOWN, 0);
      Key := 0;
      FTree.EndEditNode;
      FTree.setfocus;
     end;
 End; //case

end;

function TStringEditLink.BeginEdit: Boolean; begin

 Result := True;
 //FEdit.Height:=(FTree.DefaultNodeHeight - 1); //Needed for editbox. Not combo
 FEdit.Show;
 TComboBox(FEdit).DroppedDown:=True;
 FEdit.SetFocus;

end;

function TStringEditLink.CancelEdit: Boolean; begin

 Result := True;
 FEdit.Hide;

end;

function TStringEditLink.EndEdit: Boolean; var

 S: WideString;

begin

 Result := True;
 S:= TComboBox(FEdit).Text;
 FTree.Text[FNode, FColumn] := S;
 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 := TComboBox.Create(nil);
  with FEdit as TComboBox do
    begin
         Visible := False;
         Parent := Tree;
         Items.Add('Google');
         Items.Add('Yahoo');
         Items.Add('Altavista');
         OnKeyDown := EditKeyDown;
     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;

End.</delphi>

  • After saving the file, on the Form Designer select VST and on Object Inspector's Properties, scroll to TreeOptions -> MiscOptions, set toEditable to True. Then get to TreeOptions -> SelectionOptions, set toExtendedFocus to True.
  • Switch to Object Inspector's Events tab. Scroll to OnCreateEditor, double click and paste:

<delphi>procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree;

 Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);

begin

 EditLink:=TStringEditLink.Create;

end;</delphi>

  • On Object Inspector's Events tab. Scroll to OnNewText, double click and paste:

<delphi>procedure TForm1.VSTNewText(Sender: TBaseVirtualTree; Node: PVirtualNode;

 Column: TColumnIndex; NewText: WideString);

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;</delphi> Run program, select a node and press F2 to get combobox. On pressing Enter new value should appear on the node.

If Cell Editing Can't Be Seen

Open VirtualStringTree.pas unit file (if you are still on the above example project, right click on VirtualStringTree under Uses clause and select Find Declaration. This opens the file on next tab. Go to that file's tab.). Get to the "function TStringEditLink.BeginEdit: Boolean; stdcall;". It looks like: <delphi>function TStringEditLink.BeginEdit: Boolean; stdcall;

// Notifies the edit link that editing can start now. Descentants may cancel node edit // by returning False.

begin

 Result := not FStopping;
 if Result then
 begin
   FEdit.Show;
   FEdit.SelectAll;
   FEdit.SetFocus;
 end;

end;</delphi>

Now add "FEdit.Height:=18;". It should look like:

<delphi>function TStringEditLink.BeginEdit: Boolean; stdcall;

// Notifies the edit link that editing can start now. Descentants may cancel node edit // by returning False.

begin

 Result := not FStopping;
 if Result then
 begin
   FEdit.Show;
   FEdit.SelectAll;
   FEdit.SetFocus;
   FEdit.Height:=18; // <--- Added this line.
 end;

end;</delphi>

Save the file (press Ctrl + S). If you are on the example project, close this (Project -> Close Project). Click on Tools -> Configure "Build Lazarus" ... Select Clean Up + Build All and then click on the Build button. After compile Lazarus should be restarted. Now open the example project and try to edit node on VST. This time it should be ok.


External links


(In progress)

[En desarrollo]