In der Hilfe zu TComponent.ComponentCount steht: "ComponentCount returns the number of components that the current component owns. It can be used to determine the valid index range in the Component array". Wichtig ist das Wort "owns": Der "Owner" einer Komponente ist dafür verantwortlich, die Komponente wieder aufzuräumen, wenn sie nicht mehr gebraucht wird. Der Owner wird in der Regel (immer?) beim Erzeugen angegeben. Bei den Standardkomponenten ist das fast immer das Formular, in dem sich die Komponente befindet.
Zu TWinControl.ControlCount findet man: "The number of immediate child controls". Hier liegt die Betonung auf "immediate". Das heißt, ControlCount liefert die Controls, die sich direkt in einem "Container"-Control befinden.
Jetzt ein Beispiel:
Nimm ein Formular (Form1), auf dem sich ein Edit und ein Panel (Panel1) befinden. In dem Panel sind zwei weitere Edits. Aufgabe ist es, mit ComponentCount bzw. ControlCount die Edits zu zählen, und zwar durch Aufrufe von Form1.ComponentCount bzw .ControlCount und von Form1.Panel1.ComponentCount / .ControlCount.
(1) ComponentCount, vom Formular aus aufgerufen, findet den Wert 3, weil alle drei Edits den Formular "gehören", also von ihm zerstört werden dürfen,
(2) ComponentCount. vom Panel aus aufgerufen, ergibt 0, weil das Panel die sich darauf befindenden Edits nicht zerstören darf, das macht ja das Formular
(3) ControlCount vom Formular aus aufgerufen, ergibt 1 - es ist nur 1 edit direkt auf dem Formular, die beiden anderen stecken in dem Panel
(4) ControlCount vom Panel aus aufgerufen, ergibt 2 - es enthält nur diese beiden Edits.
Nur zur Rekursion:
Wenn in dem Panel sich ein weiteres Panel (Panel2) mit einem Edit befindet und du musst alle Edits zählen, die sich direkt im 1.Panel (Panel1) und indirekt im 2.Panel befinden, musst du zuerst die Controls auf Panel1 durchlaufen: Wenn du ein Edit findest, wird es gezählt, wenn du ein Panel findest, musst du dieses Panel in genau derselben Weise durchlaufen wie Panel1. Genau das ist ein rekursiver Prozess.
Wir brauchen eine Prozedur - nennen wir sie CountEdit -, die auf ein beliebiges TWinControl angewendet werden kann; das WinControl wird als Parameter übergeben. In dieser Prozedur machen wir genau das, was oben beschrieben ist. Inbesondere ruft diese Prozedur sich mit jedem gefundenen Panel immer wieder selbst auf. Dass das ganze ein Ende findet, funktioniert nur, weil es irgendwann Controls gibt, die keine weiteren Controls mehr enthalten. Und ich sollte natürlich noch erwähnen, dass das ganze nicht nur für Panels funktioniert, sondern für alle TWinControls:
Code: Alles auswählen
procedure CountEdit(AParent: TWinControl; var Count: Integer);
var
i: Integer;
begin
// 1.fall - AParent ist selbst ein Edit (zur Vereinfachung soll der Name mit "Edit" beginnen")
if Pos('Edit', AParent.Name) = 1 then
inc(Count)
else
// 2.fall - alle "Kinder" von AParent durchlaufen und für jedes wieder "CountEdit" aufrufen
for i:=0 to AParent.ControlCount-1 do
CountEdit(AParent.Controls[i], Count);
end;
Diese Prozedur rufst du für das Control auf, das du untersuchen willst, also Form1.Panel1. Wichtig noch: nicht vergessen den Zähler auf null zu setzen
Code: Alles auswählen
begin
Count := 0;
CountEdit(Form1.Panel1, Count);
end;
Ich gebe dir recht, Rekursion ist am Anfang etwas schwer zu verstehen, aber sie ist in meinen Augen ein extrem eleganter Algorithmus. Ohne sie wären "beliebig" große Baumstrukturen wie eine Orderstruktur auf einer Festplatte nicht zu handhaben.