VirtualTreeview Example for Lazarus/pl

From Lazarus wiki

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

Oto kilka przykładów użycia VirtualTreeview dla Lazarusa (testowane na win32). Są one w większości zebrane z sieci, napisane dla Delphi oraz z samouczka/dokumentacji autorstwa Philippa Frenzela i Mike'a Lischke.

Samouczek/dokumenty dostępne kiedyś były na stronie http://www.soft-gems.net. Obecnie dokumentację w pliku pdf można pobrać ze strony documentation.help. Tutaj znajdziesz tylko szybki sposób korzystania z VirtualTreeview na Lazarus, a nie wyjaśnienia. Aby uzyskać wyjaśnienia i wiele innych funkcji/metod, pobierz oficjalne dokumenty i samouczek.

Podstawowe Drzewo Listview z 3 Kolumnami

1. Zainstaluj komponent. Uruchom Lazarusa.

2. Upuść komponent TVirtualStringTree na formę (znajdziesz go w zakładce Virtual Controls).

3. Przejdź do edytora źródeł (naciśnij klawisz F12). W sekcji Uses dodaj moduł o nazwie VirtualTrees (jeśli jeszcze go nie ma i nie jest to VirtualStringTree). Może to wyglądać następująco:

uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  VirtualStringTree, VirtualTrees;

4. Przejdź do projektanta formularzy (naciśnij klawisz F12). Wybierz Virtual Tree Component. Na Inspektorze obiektów kliknij Nazwa, wpisz VST i naciśnij enter. Kliknij Nagłówek (rozwiń go) -> Kolumny, kliknij mały przycisk obok „0 items”. Kliknij 3 razy przycisk Dodaj, aby dodać 3 kolumny. Nie zamykaj tego okna.

5. W oknie Edycja kolumny jest teraz wybrana trzecia kolumna. Dostań się do Inspektora obiektów. Kliknij Options (rozwiń) -> ustaw coAllowClick na False.

6. Kliknij tekst. Wpisz Kolumna2.

7. Kliknij opcję Width, wpisz 100 i naciśnij klawisz Enter.

8. Przejdź do okna Edycja kolumny, wybierz pierwszą i drugą kolumnę i ustaw ich właściwość jak powyżej (w polu tekstowym użyj różnych nazw, np. Kolumna0, Kolumna1).

9. Zamknij okno edycji kolumn. Wybierz komponent Virtual Tree na formie. W Inspektorze obiektów przejdź do Header -> Options (rozwiń). Ustaw hoVisible na True.

10. Przewiń w dół, aby ustawić Header -> Style na hsFlatButtons.

ExempleVirtualtreeView1.jpg

11. Przewiń w dół do TreeOptions (rozwiń) -> MiscOptions (rozwiń) i ustaw toEditable na True. Ustaw toGridExtensions na True.

12. Przewiń w dół do SelectionOptions (rozwiń) -> ustaw toExtendedFocus na True. Ustaw toMultiSelect na True. W formularzu Form Designer zmień rozmiar VST (Virtual Tree Component), aby w razie potrzeby wyświetlić wszystkie kolumny.

13. Teraz dodaj 3 przyciski do formularza. Pobierz je z palety komponentów - Zakładka Standard (ikona z etykietą „Ok”).

14. Kliknij Button1, w Inspectorze obiektów zmień Caption na AddRoot. Kliknij Button2, zmień podpis na AddChild. Zmień podpis przycisku Button3 na Delete.

ExempleVirtualtreeView2.jpg

15. Zachowaj to tutaj i przejdź do edytora źródeł (naciśnij F12). W edytorze źródeł zamień wiersz:

{$mode objfpc}{$H+}

na

{$MODE DELPHI}

16. Pod słowem kluczowym "implementation" wklej następujące wiersze:

type
  PTreeData = ^TTreeData;
  TTreeData = record
    Column0: String;
    Column1: String;
    Column2: String;
  end;

17. Przejdź do projektanta formularzy (naciśnij klawisz F12). Wybierz VST. Przejdź do Inspektora obiektów, wybierz kartę Zdarzenia, przewiń w dół do zdarzenia onChange. Kliknij dwukrotnie combobox. Wklej następujący kod:

procedure TForm1.VSTChange(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  VST.Refresh;
end;

18. Przewiń do opcji onFocusChanged. Kliknij dwukrotnie i wklej następujący kod:

procedure TForm1.VSTFocusChanged(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Column: TColumnIndex);
begin
  VST.Refresh;
end;

19. Przewiń do onFreeNode. Kliknij dwukrotnie i wklej następujący kod:

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;

20. Przewiń w dół do onGetNodeDataSize. Kliknij dwukrotnie i wklej następujący kod:

procedure TForm1.VSTGetNodeDataSize(Sender: TBaseVirtualTree; var NodeDataSize: Integer);
begin
  NodeDataSize := SizeOf(TTreeData);
end;

21. Przewiń do onGetText. Kliknij dwukrotnie i wklej następujący kod:

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;

22. Naciśnij klawisz F12, aby przejść do projektanta formularzy. Kliknij dwukrotnie przycisk AddRoot. Wklej następujący kod:

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;

23. Naciśnij klawisz F9, aby uruchomić projekt w celu sprawdzenia. Kliknij AddRoot, aby dodać węzeł. Jeśli jest w porządku, węzeł zostanie dodany na VST.

ExempleVirtualtreeView3.jpg

24. Zatrzymaj wykonywanie. W formularzu kliknij dwukrotnie przycisk podpisany jako AddChild. Wklej następujący kod:

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;

25. W formularzu kliknij dwukrotnie przycisk podpisany jako Delete. Wklej następujący kod:

procedure TForm1.Button3Click(Sender: TObject);
begin
  VST.DeleteSelectedNodes;
end;

26. Uruchom projekt, naciskając klawisz F9, aby sprawdzić program. Dodaj węzeł, dziecko i usuń je.

ExempleVirtualtreeView4.jpg

27. Spróbuj edytować węzeł. Wybierz węzeł i naciśnij F2, wpisz nową wartość. Jeśli widzisz, co piszesz, to jest OK. W przeciwnym razie przeczytaj poniżej „Nie można zobaczyć edycji komórki”.

28. Aby VST pokazywał nową wartość wprowadzoną po edycji, przejdź do Projektanta formularzy, wybierz VST. W Inspektorze obiektów -> Zdarzenia -> zdarzenie OnNewText kliknij dwukrotnie. Wklej następujący kod:

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;

Na tym przykład podstawowego zastosowania kończy się. Możesz upuścić kilka dodatkowych przycisków na formularz, aby przetestować kilka innych poleceń podanych poniżej. Następnymi krokami byłoby pokazanie pola wyboru, obrazu, koloru czcionki i dodanie combobox w węźle.

  • Inny sposób na dodanie węzła głównego
procedure TForm1.Button8Click(Sender: TObject);
begin
  with VST do
    RootNodeCount := RootNodeCount + 1;
end;
  • Inny sposób na dodanie dziecka
procedure TForm1.Button9Click(Sender: TObject);
begin
  if Assigned(VST.FocusedNode) then
    VST.ChildCount[VST.FocusedNode] := VST.ChildCount[VST.FocusedNode] + 1;
end;
  • Wybierz i usuń dzieci węzła
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;
  • Usunięcie węzeł
procedure TForm1.Button5Click(Sender: TObject);
begin
{VST.Clear;  //Delete All Nodes}
  if not Assigned(VST.FocusedNode) then
    Exit;
  VST.DeleteNode(VST.FocusedNode);
end;
  • Wyszukaj i wybierz węzeł
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;
  • Wybierz rodzica
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;
  • Wyszukaj wszystko
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;
  • Wyszukaj następny
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;
  • Wstaw węzeł
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;
  • Ustaw wysokość węzła
procedure TForm1.Button14Click(Sender: TObject);
begin
  if Assigned(VST.FocusedNode) then
    VST.NodeHeight[VST.FocusedNode] := 32;
end;
  • Zapisz i załaduj

Proste drzewo (bez kolumn) można zapisać i załadować jako:

VST.SaveToFile('filename.dat');
VST.LoadFromFile('filename.dat');

Aby zapisać i załadować powyższy przykład, umieść 2 przyciski w formularzu, zmień nazwę Caption na „Save” i „Load”. Wybierz VST, w Inspektorze obiektów -> TreeOptions -> StringOptions upewnij się, że parametr toSaveCaptions ma wartość True. Przejdź do zakładki Zdarzenia Inspektora obiektów. Przewiń w dół do OnLoadNode, kliknij dwukrotnie, a następnie wklej kod:

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;

Ponownie na karcie Zdarzenia Inspektora obiektów - przewiń w dół do OnSaveNode, kliknij dwukrotnie, i wklej kod:

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;

W formularzu kliknij dwukrotnie przycisk "Save" i wklej kod:

procedure TForm1.Button10Click(Sender: TObject);
begin
  VST.SaveToFile('C:\vst.dat');
end;

W formularzu kliknij dwukrotnie przycisk "Load" i wklej kod:

procedure TForm1.Button11Click(Sender: TObject);
begin
  VST.LoadFromFile('C:\vst.dat');
end;

Teraz przetestuj zapisywanie i ładowanie drzewa.

  • Problem z przewijaniem

Nagłówek widoku drzewa znika całkowicie lub częściowo podczas przewijania. Nie mogłem znaleźć na to dobrego rozwiązania. Jednym ze sposobów rozwiązania tego problemu jest ustawienie wysokości nagłówka na 0, a następnie użycie ogólnej etykiety dla kolumn. Jest to dobre, gdy jest kilka kolumn i wszystkie są widoczne bez przewijania w poziomie. Lub wysokość nagłówka można ustawić na wyższą wartość, np. 25 lub 30. VST.Refresh można dodać do zdarzenia OnScroll.
W wersji 5.5.3.1 nie zaobserowałem tego efektu, więc prawdopodobnie został on naprawiony.

  • Zmiana rozmiaru kolumny

Nie można zmienić rozmiaru kolumny, przeciągając myszą nagłówek VST. Może to być błąd nagłówka lub coś przeoczyłem. Jeśli dotyczy nagłówka, prawdopodobnie zostanie naprawiony w następnej wersji Lazarus. Zobacz ten link: http://bugs.freepascal.org/view.php?id=11209
W wersji 5.5.3.1 nie zaobserowałem tego efektu, więc prawdopodobnie został on naprawiony.

Poniższy kod może być przydatny dla tych, którzy chcieliby go sprawdzić lub wykorzystać w jakimś innym celu.

W każdym razie można zmienić rozmiar kolumny z kodu. Po naciśnięciu prawego przycisku myszy i przesunięciu kółka myszy w górę szerokość wybranej kolumny zwiększa się, a następnie naciśnięcie prawego przycisku myszy i przesunięcie kółka myszy w dół, aby zmniejszyć szerokość wybranej kolumny. Aby to zrobić:

1. Dodaj zmienną w edytorze źródłowym o nazwie CurCol: Integer; Wygląda to tak:

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

implementation

{ TForm1 }

2. W Projektancie formularzy kliknij dwukrotnie formularz, aby wygenerować zdarzenie OnCreate. Wewnątrz procedury OnCreate wpisz Form1.OnMouseWheelUp:= i naciśnij Ctrl+Shift+C, spowoduje to uzupełnienie kodu i utworzenie szkieletu zdarzenia MouseWheelUp. Wróć teraz do procedury TForm1.FormCreate(Sender: TObject); i dodaj kolejne wydarzenie dla MouseWheelDown. Wpisz Form1.OnMouseWheelDown:= i naciśnij Ctrl+Shift+C, aby wygenerować zdarzenie MouseWheelDown. Procedura FormCreate wygląda teraz następująco:

procedure TForm1.FormCreate(Sender: TObject);
begin
  Form1.OnMouseWheelUp   := @Form1MouseWheelUp;
  Form1.OnMouseWheelDown := @Form1MouseWheelDown;
end;

3. Wypełnij procedurę TForm1.Form1MouseWheelUp w ten sposób:

procedure TForm1.Form1MouseWheelUp(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if VST.Focused and (ssRight in Shift) then
    VST.Header.Columns[CurCol].Width := VST.Header.Columns[CurCol].Width + 10;
end;

4. Wypełnij procedurę TForm1.Form1MouseWheelDown jak poniżej:

procedure TForm1.Form1MouseWheelDown(Sender: TObject; Shift: TShiftState;
  MousePos: TPoint; var Handled: Boolean);
begin
  if VST.Focused and (ssRight in Shift) then
    VST.Header.Columns[CurCol].Width := VST.Header.Columns[CurCol].Width - 10;
end;

5. Przejdź do Projektanta formularzy (naciśnij F12), wybierz VST, na karcie Zdarzenia Inspektora obiektów przewiń do OnFocusChanged, kliknij dwukrotnie i wklej:

procedure TForm1.VSTFocusChanged(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex);
begin
  CurCol := Column;
end;

Po uruchomieniu programu kliknij kolumnę, a następnie przytrzymaj prawy przycisk myszy i przesuń kółko w górę, aby zwiększyć szerokość, lub kółko w dół, aby ją zmniejszyć. W razie potrzeby możesz dostosować powyższe procedury. Możesz też dodać zdarzenie klawiatury z czymś takim jak "if (key=187) i (ssShift in Shift) then", aby reagować na naciśnięcie klawiszy Shift + "+".

Pole wyboru (CheckBox)

On Form Designer select VST. Go to: W formularzu wybierz VST i wykonaj:

  1. Inspektor obiektów -> Właściwości -> CheckImageKind i wybierz ckDarkCheck.
  2. Inspektor obiektów -> Właściwości -> TreeOptions -> MiscOptions -> toCheckSupport i ustaw na True.

Teraz przejdź do zakładki Zdarzenia.

  • Przewiń do OnInitNode. Kliknij dwukrotnie i wklej następujący kod:
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;

Uruchom program, dodaj węzeł i dziecko, a następnie dodaj dziecko do dziecka, i sprawdź, czy możesz poprawnie zaznaczyć i odznaczyć pola wyboru. Jeśli nie, zamknij program. Przejdź do zakładki Zdarzenia Inspektora obiektów.

  • Przewiń do OnChecked, kliknij dwukrotnie i wklej:
procedure TForm1.VSTChecked(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  VST.Refresh;
end;
  • Przewiń do opcji OnChecking, kliknij dwukrotnie i wklej:
procedure TForm1.VSTChecking(Sender: TBaseVirtualTree; Node: PVirtualNode;
  var NewState: TCheckState; var Allowed: Boolean);
begin
  VST.Refresh;
end;

Mam nadzieję, że teraz jest ok. Aby określić stan pola wyboru, użyj:

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

Inne stany to:

csUncheckedNormal = niezaznaczone i nie wciśnięte
csUncheckedPressed = niezaznaczone i wciśnięte
csCheckedNormal = zaznaczone i nie wciśnięte
csCheckedPressed = zaznaczone i wciśnięte
csMixedNormal = 3-stanowe pole wyboru i nie wciśnięte
csMixedPressed = 3-stanowe pole wyboru i wciśnięte

Inne typy to:

ctNone
ctTriStateCheckBox
ctCheckBox
ctRadioButton
ctButton
  • Aby przechwycić przycisk pola wyboru (ctButton) Click

Przejdź do zakładki Zdarzenia Inspektora obiektów. Przewiń do OnChecked, kliknij dwukrotnie i wklej kod:

procedure TForm1.VSTChecked(Sender: TBaseVirtualTree; Node: PVirtualNode);
begin
  if Node^.CheckType = ctButton then
    ShowMessage('Ok.');
  VST.Refresh;
end;

Koniec pola wyboru.

Obrazy

Aby wyświetlić obrazy w węzłach VST, należy utworzyć listę obrazów.

  • Przejdź do palety komponentów -> Common Controls. Wybierz i upuść składnik TImageList na formularzu. Kliknij prawym przyciskiem myszy ikonę komponentu i wybierz ImageList Editor. Kliknij przycisk Dodaj i wybierz kilka zdjęć (na razie co najmniej 3), a następnie kliknij przycisk wyboru, aby zaakceptować i zamknąć Edytor ImageList. Nawiasem mówiąc, istnieje kilka fajnych zdjęć, które można pobrać ze strony http://www.famfamfam.com/lab/icons/silk/
  • Teraz w Projektancie formularzy wybierz VST, a na karcie Właściwości Inspektora obiektów przewiń do Images i wybierz ImageList1
  • Na karcie Zdarzenia Inspektora obiektów przewiń do OnGetImageIndex, kliknij dwukrotnie i wklej kod:
procedure TForm1.VSTGetImageIndex(Sender: TBaseVirtualTree; Node: PVirtualNode;
  Kind: TVTImageKind; Column: TColumnIndex; var Ghosted: Boolean;
  var ImageIndex: Integer);
begin
  if Kind in [ikNormal , ikSelected] then // Zarówno wybrane jak i nie
  begin
    if Column = 0 then                    // jeśli to pierwsza kolumna
      ImageIndex := 0;                    // pierwszy obraz z listy ImageList1

    if Column = 1 then                    // jeśli to druga kolumna
      ImageIndex := 1;                    // drugi obraz z listy ImageList1

    if Sender.FocusedNode = Node then     // Pokaż tylko, jeśli wybrany
      if Column = 2 then                  // jeśli to trzecia kolumna
        ImageIndex := 2;                  // trzeci obraz z listy ImageList1
  end;
  {Sender.NodeHeight[node] := 40; //Jeśli obraz jest duży}
end;

Kolor czcionki

W Projektancie formularzy wybierz VST, a na karcie Zdarzenia Inspektora obiektów przewiń do OnPaintText, kliknij dwukrotnie i wklej kod:

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 = 'niebo' 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;

Teraz uruchom program. Dodaj jakieś węzły. Zobaczysz, że tekst w drugiej kolumnie jest czerwony. Spróbuj teraz zmienić tekst jakiegoś węzła w pierwszej kolumnie (klawisz F2) wpisując słowo "niebo". Po zatwierdzeniu zmiany tekst powinien stać się niebieski.

Dodanie ComboBox

  • Myślę, że masz otwarty projekt w Lazarus IDE z VST i możesz edytować węzły. Jeśli nie, zobacz „Podstawowy widok drzewa z 3 kolumnami” powyżej i przynajmniej wykonaj kroki od 1 do 21.
  • Poniżej znajduje się treść pliku modułu o nazwie combo. Skopiuj ten moduł i zapisz jako combo.pas w katalogu projektu. Pod klauzulą uses programu dodaj nazwę mocułu combo. Może to wyglądać następująco:
uses
  Classes, SysUtils, LResources, Forms, Controls, Graphics, Dialogs,
  VirtualStringTree, VirtualTrees, combo;
  • Moduł combo.pas
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: String;
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.
  • Po zapisaniu pliku, w Projektancie formularzy wybierz VST, a we właściwościach Inspektora obiektów przewiń do TreeOptions -> MiscOptions, ustaw wartość na toEditable na True. Następnie przejdź do TreeOptions -> SelectionOptions, ustaw toExtendedFocus na True.
  • Przejdź do zakładki Zdarzenia Inspektora obiektów. Przewiń do OnCreateEditor, kliknij dwukrotnie i wklej kod:
procedure TForm1.VSTCreateEditor(Sender: TBaseVirtualTree;
  Node: PVirtualNode; Column: TColumnIndex; out EditLink: IVTEditLink);
begin
  EditLink := TStringEditLink.Create;
end;
  • W zakładce Zdarzenia Inspektora obiektów przewiń do OnNewText, kliknij dwukrotnie i wklej kod:
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;

Uruchom program, wybierz węzeł i naciśnij F2, aby uzyskać ComboBox. Po naciśnięciu wprowadź nową wartość, a powinna ona pojawić się w węźle.

Jeśli nie można zobaczyć edycji komórki

Otwórz plik modułu VirtualStringTree.pas (jeśli nadal pracujesz nad powyższym przykładowym projektem, kliknij prawym przyciskiem myszy VirtualStringTree w obszarze słowa kluczowego uses i wybierz Znajdź deklarację. Spowoduje to otwarcie pliku na następnej karcie. Przejdź do zakładki tego pliku). Przejdź do „funkcji TStringEditLink.BeginEdit: Boolean; stdcall;”. To wygląda jak:

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;

Teraz dodaj "FEdit.Height:=18;". Powinno to wyglądać następująco:

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;

Zapisz plik (naciśnij Ctrl + S). Jeśli korzystasz z przykładowego projektu, zamknij go (Projekt -> Zamknij projekt). Kliknij Narzędzia -> Konfiguruj "Build Lazarusa" ... W Profilu budowania wybierz Czyść + Buduj wszystko, a następnie kliknij przycisk Buduj. Po kompilacji należy ponownie uruchomić Lazarusa. Teraz otwórz przykładowy projekt i spróbuj edytować węzeł na VST. Tym razem powinno być dobrze.

Linki zewnętrzne