vložil Radek Červinka
24. října 2012 22:36
Moc se mi líbí způsob vyhledávání ala Windows 7 nebo novější Delphi IDE, tj. začnete psát a zobrazují se vám jen relevantní záznamy. Přemýšlel jsem, jak je to těžké udělat pro můj milovaný švýcarský nůž mezi komponentami aka TVirtualTreeView. Jelikož právě v Delphi IDE je použit modifikovaný VirtualTreeView tak jsem doufal, že to až takový problém nebude. A nebyl.

Předpokládám, že máte přečteny minulé díly seriálu o VT - jsou dostupné přes tag na konci článku.
Uzel stromu (tedy PVirtualNode) má kromě jiných možných stavů i stav vsFiltered, který se nastavuje a (nejlépe) zjišťuje přes property stromu IsFiltered … a to je v podstatě vše - zbytek zařídí VT.
Následující kód rekurzivně projde strom a nechá zobrazené jen ty uzly, co obsahují filtr (na obrázku jen s "zá"). Je to část většího kódu a nechtěl jsem to moc upravovat - proto se některé části dají napsat kratší.
PVTNavigatorRec je v mém případě record obsahující virtuální data - viz minulé díly. U vás to bude něco jiného.
Volání (vt je strom) je pak:
mUpdateFilter(vt.RootNode, AnsiUppercase(Trim(edtSearch.Text)));
Jen bych upozornil na řádek 41 a 45, kdy v prvním případě je porovnání, v druhém pak zajištění, že celá cesta k uzlu bude rozbalena.
1procedure TfrmNavigator.mUpdateFilter(pParentNode:PVirtualNode; const sFilter: string);
2var
3 pNode: PVirtualNode;
4 pNodeData: PVTNavigatorRec;
5 sText: string;
6 bChildrenVisible: Boolean;
7 b: Boolean;
8
9 function mbAreChildrenVisible(pParent:PVirtualNode):Boolean;
10 var
11 p: PVirtualNode;
12 begin
13 p := pParent.FirstChild;
14 Result := False;
15 while p <> nil do
16 begin
17 Result := not vt.IsFiltered[p];
18 if Result then
19 Exit;
20 p := p.NextSibling;
21 end;
22 end;
23begin
24 if (pParentNode = nil) or (pParentNode.ChildCount = 0) then
25 Exit;
26 pNode := pParentNode.FirstChild;
27 while pNode <> nil do
28 begin
29 if pNode.ChildCount <> 0 then
30 begin
31 mUpdateFilter(pNode, sFilter);
32 bChildrenVisible := mbAreChildrenVisible(pNode);
33 vt.IsFiltered[pNode] := not bChildrenVisible;
34 end
35 else
36 begin
37 if sFilter <> '' then
38 begin
39 pNodeData := vt.GetNodeData(pNode);
40 sText:= pNodeData^.sCaption;
41 b := AnsiPos(sFilter, AnsiUppercase(sText)) = 0;
42 vt.IsFiltered[pNode] := b;
43 if not b then
44 begin
45 vt.VisiblePath[pNode] := True;
46 end;
47 end
48 else
49 vt.IsFiltered[pNode] := False;
50 end;
51 pNode := pNode.NextSibling;
52 end;
53end;
Podle mne to opět dokazuje jak je VT perfektní navržený nástroj.