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.
procedure TfrmNavigator.mUpdateFilter(pParentNode:PVirtualNode; const sFilter: string);
var
pNode: PVirtualNode;
pNodeData: PVTNavigatorRec;
sText: string;
bChildrenVisible: Boolean;
b: Boolean;
function mbAreChildrenVisible(pParent:PVirtualNode):Boolean;
var
p: PVirtualNode;
begin
p := pParent.FirstChild;
Result := False;
while p <> nil do
begin
Result := not vt.IsFiltered[p];
if Result then
Exit;
p := p.NextSibling;
end;
end;
begin
if (pParentNode = nil) or (pParentNode.ChildCount = 0) then
Exit;
pNode := pParentNode.FirstChild;
while pNode <> nil do
begin
if pNode.ChildCount <> 0 then
begin
mUpdateFilter(pNode, sFilter);
bChildrenVisible := mbAreChildrenVisible(pNode);
vt.IsFiltered[pNode] := not bChildrenVisible;
end
else
begin
if sFilter <> '' then
begin
pNodeData := vt.GetNodeData(pNode);
sText:= pNodeData^.sCaption;
b := AnsiPos(sFilter, AnsiUppercase(sText)) = 0;
vt.IsFiltered[pNode] := b;
if not b then
begin
vt.VisiblePath[pNode] := True;
end;
end
else
vt.IsFiltered[pNode] := False;
end;
pNode := pNode.NextSibling;
end;
end;
Podle mne to opět dokazuje jak je VT perfektní navržený nástroj.