Hallo Micha,
mit dem von gothic_mike vorgeschlagenen Ansatz, zählst Du faktisch die "Anzahl vorgenommenen Rotfärbungen beim Zeichnen". Dieser Ansatz ist in sofern kritisch, als dass Du nicht sicherstellen kannst, dass wirklich jeder Knoten gezeichnet wird (außerhalb des ClientRects des Trees, Invisible, minimierter Zweig, etc) und Du keine unmittelbare Einflussmöglichkeit auf das Eintreten des Zeitpunkts des zeichnen kannst, so dass auch ein Einsatz der Form
Delphi-Quellcode:
Self.FGefunden:= 0;
Self.EdtSuchen.Text:= SomeValue;
ShowMessage(IntToStr(Self.FGefunden));
keine brauchbare Lösung bietet.
Du wirst nicht um ein Traversieren (alle Knoten einer Struktur durchlaufen) herum kommen und jeden Knoten erneut gegen das Kriterium prüfen müssen. Leider kenne ich zu diesem Zweck keine vorgefertigte Methode, die mit einer CallBack-Funktion aufgerufen werden kann und das Missbrauchen von
CustomSort halte ich ebenfalls für kritisch.
Aus diesem Grund biete ich Dir an dieser Stelle eine entsprechene Traversierungsmethode für Deinen Spezialfall an. Zunächst führe ich hierzu die private Methode
DoesNodeMatchCriteria ein, die genau dann
True zurückgibt, wenn ein Knoten das von Dir beschriebene Kriterium erfüllt:
Delphi-Quellcode:
function TForm1.DoesNodeMachCriteria(const ANode: TTreeNode): Boolean;
begin
Result:= AnsiStartsText(Self.EdtSuchen.Text, ANode.Text);
end;
so dass zunächst Deine Zeichenroutine vereinfacht werden kann:
Delphi-Quellcode:
procedure TForm1.treeCustomDrawItem(Sender: TCustomTreeView;
Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean);
begin
if DoesNodeMatchCriteria(Node) then
Sender.Canvas.Font.Color:= clRed;
end;
anschließend führe ich die tatsächliche Zählmethode
CountMatchingNodes ein:
Delphi-Quellcode:
function TForm1.CountMatchingNodes: Cardinal;
procedure TraverseNodes(const ANode: TTreeNode; var ASum: Cardinal);
var
myNode: TTreeNode;
begin
myNode:= ANode;
// iterate every node at this level
while Assigned(myNode) do
begin
if DoesNodeMatchCriteria(myNode) then
Inc(ASum);
// traverse recursive
TraverseNode(myNode.getFirstChild, ASum);
myNode:= myNode.getNextSibling;
end;
end;
begin
Result:= 0;
TraverseNodes(TreeView1.Items.GetFirstNode, Result);
end;
Sie basiert im Wesentlichen auf der Unterprozedur
TraverseNodes, die für alle Knoten auf derselben Ebene wie dem übergebenen Knoten überprüft, ob sie dem Kriterium entsprechen und einen als Referenz übergebenen Zähler um diese Anzahl erhöht
Delphi-Quellcode:
myNode:= ANode;
while Assigned(myNode) do
begin
if DoesNodeMatchCriteria(myNode) then
Inc(ASum);
myNode:= myNode.getNextSibling;
end;
weil die Unteroutine mit dem Wurzelelement des Treeviews aufgerufen wird und der als Referenz übergebene Wert dem Wert
Result von
CountMatchingNodes entspricht, zählt dieser Teil der Lösung bereits alle "roten Knoten" auf der ersten Ebene.
Um nun auch alle Unterknoten der Knoten sowie deren Unterknoten usw zu überprüfen, wende ich eine Rekursion an. Die Unterprozedur
TraverseNodes ruft "sich selbst" mit dem ersten Unterknoten der gerade betrachteten Knotens auf, so dass alle Unterknoten auf dieser Ebene überprüft werden. Weil die Routine für jeden Aufruf auf dieselbe Weise verfährt, werden letztlich alle Knoten durchlaufen und überprüft.
Um die Methode
CountMatchingNodes nun zu verwenden, kannst Du zB folgendes Schreiben
Delphi-Quellcode:
Self.EdtSuchen.Text:= SomeValue;
ShowMessage(IntToStr(CountMatchingNodes));