Link to home
Start Free TrialLog in
Avatar of jpedwards
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?
Avatar of kretzschmar
kretzschmar
Flag of Germany image

main loop

for i := 0 to screen.formcount - 1 do
begin
  //save your form-information (screen.forms[i])
  for j := 0 to screen.forms[i].controlcount - 1 do
    call_control_get_information_method(screen.forms[i].controls[j]);
....


procedure call_control_get_information_method(AControl : TControl);
begin
  //save information of AControl
  //now recursive call
  for i := 0 to AControl.Controlcount - 1 do
    call_control_get_information_method(AControl.controls[i]);
....

just as sceleton

meikl ;-)
Avatar of geobul
geobul

Hi,

procedure EnumComponents(Component: TComponent);
var
  i: integer;
begin
  if (Component is TControl) then begin
    // do your savings here
    Form1.Memo1.Lines.Add(Component.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.Components[i]);
  end;
end;

procedure TForm1.Button1Click(Sender: TObject);
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 ;-)
Hi meikl ;-) You are faster. Where have you been these days? On summer leave maybe?
ASKER CERTIFIED SOLUTION
Avatar of kretzschmar
kretzschmar
Flag of Germany image

Link to home
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
Start Free Trial
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 ;-)
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
Avatar of jpedwards

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.
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