VirtualTreeview Example for Lazarus/pl

From Free Pascal wiki
Jump to navigationJump to search

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