jpedwards
asked on
How do I make a recursive procedure that will not generate a "Stack Overflow" error?
I am writing a procedure (D3) which goes through each form in the program, saves information about the form to a database, and then goes through each of its components. (this is working)
If the component is a TControl, then I save some information about it to a database. (this is working)
I then want to see if the component has any child components, check if each of them is a TControl and if so, save some of their information to the database. I want to do this recursively to capture information about each component in the whole program. (this is not working)
It seems to me that the second routine should be recursive so that it can call itself. I have read what little there is in the Help about making a procedure recursive by using forward declarations but it is not clear to me what to do, or where to put it. Can anyone help?
If the component is a TControl, then I save some information about it to a database. (this is working)
I then want to see if the component has any child components, check if each of them is a TControl and if so, save some of their information to the database. I want to do this recursively to capture information about each component in the whole program. (this is not working)
It seems to me that the second routine should be recursive so that it can call itself. I have read what little there is in the Help about making a procedure recursive by using forward declarations but it is not clear to me what to do, or where to put it. Can anyone help?
Hi,
procedure EnumComponents(Component: TComponent);
var
i: integer;
begin
if (Component is TControl) then begin
// do your savings here
Form1.Memo1.Lines.Add(Comp onent.Name ); // remove this line
end;
// check if it owns other components
if Component.ComponentCount > 0 then begin
// call this procedure recursively for all components it owns
for i := 0 to Component.ComponentCount - 1 do
EnumComponents(Component.C omponents[ i]);
end;
end;
procedure TForm1.Button1Click(Sender : TObject);
begin
EnumComponents(Form1);
end;
Regards, Geo
procedure EnumComponents(Component: TComponent);
var
i: integer;
begin
if (Component is TControl) then begin
// do your savings here
Form1.Memo1.Lines.Add(Comp
end;
// check if it owns other components
if Component.ComponentCount > 0 then begin
// call this procedure recursively for all components it owns
for i := 0 to Component.ComponentCount - 1 do
EnumComponents(Component.C
end;
end;
procedure TForm1.Button1Click(Sender
begin
EnumComponents(Form1);
end;
Regards, Geo
just to say,
that the form-componentlist contains all components,
so, if you are working with the componentlist, you have only to iterate through the form-componentlist
-> no recursive-call is needed
meikl ;-)
that the form-componentlist contains all components,
so, if you are working with the componentlist, you have only to iterate through the form-componentlist
-> no recursive-call is needed
meikl ;-)
Hi meikl ;-) You are faster. Where have you been these days? On summer leave maybe?
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
hi geo,
>Where have you been these days?
i was a bit in vacation (10 days) with my family,
no computer, no work, was nice, but just ended :-(
meikl ;-)
>Where have you been these days?
i was a bit in vacation (10 days) with my family,
no computer, no work, was nice, but just ended :-(
meikl ;-)
Lucky meikl :-) I had no vacation this summer, lot of work... :(
In my first comment I tried to show how a recursive function has to be used because the question was about that.
Regards, Geo
In my first comment I tried to show how a recursive function has to be used because the question was about that.
Regards, Geo
ASKER
Thank both of you for your help. I have tested both methods and they each work. I am awarding the points to kretzschmar because his example was easier for me to understand.
I tried to accept this answer last week but I gues that I did something wrong and it is still open. Isn't it?
Anyway thanks to both of you.
I tried to accept this answer last week but I gues that I did something wrong and it is still open. Isn't it?
Anyway thanks to both of you.
Hi,
1. The procedure you accepted is NOT a recursive one.
2. It counts only the components owned by the root control passed as parameter (the form). If there are controls on the form that are not owned by that form (created in run-time) then they wont be saved. Example:
var edit: TEdit;
..
procedure TForm1.Button1Click(Sender : TObject);
begin
EnumComponents(Form1);
end;
procedure TForm1.Button2Click(Sender : TObject);
begin
edit := TEdit.Create(Panel1); // Panel1 is the owner
with edit do begin
Parent := Panel1;
Left := 10;
Top := 10;
Text := 'Hello';
Name := 'MyEdit'; // you wont see MyEdit in the Memo
end;
end;
My code, on the other hand, will.
A recursive function basicaly has two alternatives in its code:
- calls itself one level deeper (could be done several times at one level - for each component owned by the current component in our case);
- stops executing and this way returns one level up (the function that called it continues executing).
Its purpose is to be called once for each element of a tree. The first run is with the root. Every time there are branches owned by the current element the procedure goes one level down (and passes one of these branches as parameter to another copy of itself). If the current branch has no subtrees (i.e. it's a leaf), the current procedure doesn't go down and stops.
Regards, Geo
1. The procedure you accepted is NOT a recursive one.
2. It counts only the components owned by the root control passed as parameter (the form). If there are controls on the form that are not owned by that form (created in run-time) then they wont be saved. Example:
var edit: TEdit;
..
procedure TForm1.Button1Click(Sender
begin
EnumComponents(Form1);
end;
procedure TForm1.Button2Click(Sender
begin
edit := TEdit.Create(Panel1); // Panel1 is the owner
with edit do begin
Parent := Panel1;
Left := 10;
Top := 10;
Text := 'Hello';
Name := 'MyEdit'; // you wont see MyEdit in the Memo
end;
end;
My code, on the other hand, will.
A recursive function basicaly has two alternatives in its code:
- calls itself one level deeper (could be done several times at one level - for each component owned by the current component in our case);
- stops executing and this way returns one level up (the function that called it continues executing).
Its purpose is to be called once for each element of a tree. The first run is with the root. Every time there are branches owned by the current element the procedure goes one level down (and passes one of these branches as parameter to another copy of itself). If the current branch has no subtrees (i.e. it's a leaf), the current procedure doesn't go down and stops.
Regards, Geo
for i := 0 to screen.formcount - 1 do
begin
//save your form-information (screen.forms[i])
for j := 0 to screen.forms[i].controlcou
call_control_get_informati
....
procedure call_control_get_informati
begin
//save information of AControl
//now recursive call
for i := 0 to AControl.Controlcount - 1 do
call_control_get_informati
....
just as sceleton
meikl ;-)