0

I have a TAction.OnExecute event handler triggered from my main form, FormPrincipal, which opens other Forms.

procedure TFormPrincipal.AbreFormBancoExecute(Sender: TObject);
begin
   Formbanco              := Tformbanco.Create(self);
   Formbanco.Parent       := PanelCorpo;
   Formbanco.Align        := alclient;
   Formbanco.BorderIcons  := [];
   Formbanco.Show;
   Formbanco.BorderStyle  := bsNone;
   Formbanco.SetFocus;
end;

Once I'll have several forms, how to know which one is opened and how to close it, before triggering OnExecute to open another Form?

=========== Finally it is Working as I expected ======= The main form is form1 from which I call form2 and form3. In form1 I have a panel1 which is parent of form2 and form3. See form1 code : ... var Form1: TForm1;

implementation
{$R *.dfm}
uses unit2, unit3;

procedure Tform1.CloseActiveForm (Formname : string);
// Free memory allocated to the current form , set it to nil
// I'll have to find a better way to perform FreeanNil without
// use many IFs command
begin
     if Formname  = 'form2' then FreeAndnil(Form2) else
         if Formname = 'form3' then FreeandNil(Form3);
end;

procedure TForm1.Button1Click(Sender: TObject);
begin
       CloseActiveForm(Edit1.Text); //Edit1 has the current active form name
       if form2 = nil  then
       begin
              Application.CreateForm(Tform2,Form2);
              Form2.Parent  := Panel1;
              Form2.Align   := alclient;

              Form2.Show;
              Form2.BorderStyle :=  bsnone;
              Form2.SetFocus;
              Form2.OnActivate(Sender); //Method Show blocks Activate event
      end;    
end;

procedure TForm1.Button2Click(Sender: TObject);
begin
       CloseActiveForm(Edit1.Text); //Edit1 has the current active form name
       if form3 = nil  then
        begin
              Application.CreateForm(Tform3,Form3);
              Form3.Parent  := Panel1;
              Form3.Align   := alclient;

              Form3.Show;
              Form3.BorderStyle := bsnone;
              Form3.SetFocus;
              Form3.OnActivate(Sender);  //Method Show blocks Activate event             
        end;
end;

procedure TForm1.FormActivate(Sender: TObject);
begin
   Edit1.Text := Screen.ActiveForm.Name;
end;
end.

2) Code in form2 and form3 (consider form3 is identical)

...

var
  Form2: TForm2;

implementation

{$R *.dfm}
uses unit1;

procedure TForm2.Button1Click(Sender: TObject);
begin
       Edit2.Text := Screen.ActiveForm.Name;
end;

procedure TForm2.FormActivate(Sender: TObject);
begin
     setfocus;
     Edit1.Text       := Form2.Name;
     Form1.Edit1.Text := Form2.Name; //set form name 

// the property Screen.ActiveForm.Name if used here, will always presents
// form1 name (main form) because this form2 is set to a parent panel 
// in form1
end;  

end.

enter image description here

enter image description here

JRG
  • 513
  • 9
  • 23
  • 2
    `Screen.Forms` is an indexed property by which you can reach existing forms. – Victoria Sep 18 '17 at 05:20
  • 1
    If you just want to prevent multiple instances of `TFormBanco`, check your `Formbanco` variable for nil before calling `TFormBanco.Create()`, and when the Form is destroyed, have its `OnDestroy` event reset the variable to nil. You can have the Form's `OnClose` event trigger destruction by setting the event's `Action` parameter to `caFree`. – Remy Lebeau Sep 18 '17 at 05:25
  • This code is really mixed up, Can you tell us why you want to use a form for this particular task? What is you are really wanting to do? – Nasreddine Galfout Sep 20 '17 at 17:46
  • post the edit as an answer @jrg – Nasreddine Galfout Sep 21 '17 at 20:04
  • Nasreddine, my goal is to have a main form(form1) calling other forms (form2,form3,form-n) and present the called forms inside a panel in the form1. I'll use a Ttoolbar wit Tbuttons, one for each form to perform the call. Before to open each form, I have to guarantee that the current one active will be closed and free, in order to avoid multiples instance of the same form. Is there another way to implement this ? i.e. having multiples forms opened inside a panel of the major form ? If so, please help e to know that. Thank you for your support. – JRG Sep 21 '17 at 21:04
  • a) IMHO you are using forms like a panel (you strip your forms leaving only the client area). you can not move or resize them, so it is point less to use a hall class like `TForm` when you have a suitable container like `TPanel`. b) what you are using to determine the active form is wrong it does not do what you think `FormPrincipal` is still the active form. What you are doing is just setting the name of the newly created form in your `TEdit` which you can do if you use panels. – Nasreddine Galfout Sep 22 '17 at 08:38
  • And there is another way to do what you want use option one in my answer and just change the name of the form (use different names like `Formbanco`,`Formbanco1`...`FormbancoN`) and for each button have the right code for each form and you are done – Nasreddine Galfout Sep 22 '17 at 08:55
  • I updated my answer for this – Nasreddine Galfout Sep 22 '17 at 08:55
  • Nasreddine, great ! Thanks for sharing your opinions and reccomendations. I'll review my code and improve it based in your highlights. You gave me a good help ! – JRG Sep 26 '17 at 15:28

1 Answers1

0

Destroy the form if it exist and create a new instance of it.

procedure TFormPrincipal.AbreFormBancoExecute(Sender: TObject);

  procedure CreateFormbanco;
    begin
    Formbanco               := TFormbanco.Create(self);
    Formbanco.Parent       := PanelCorpo;
    Formbanco.Align        := alclient;
    Formbanco.BorderIcons  := [];
    Formbanco.BorderStyle  := bsNone;
    Formbanco.Show;
    Formbanco.SetFocus;
    Formbanco.OnDestroy    := FormDestroyEvent;
    end;

begin
if not Assigned(Formbanco) then
  begin
  CreateFormbanco;
  end
else
  begin
  Formbanco.Destroy;
  CreateFormbanco;
  end;

procedure TFormPrincipal.FormDestroyEvent(Sender: TObject);
begin
  Formbanco := nil;
end;

This code will check if Formbanco existed, if so it will destroy it and create a new instance of it otherwise it will create a new one.

Edit: create different forms and use the code above, just change Formbanco and TFormbanco to their respected new form name.

Nasreddine Galfout
  • 2,550
  • 2
  • 18
  • 36
  • This code scans all existing form in order to get one that is visible. Is it possible to know which one is visible and activated (focus in) without to scann all of them? I tried to use Screen.Activeform.Name but it only returns the caller form but never the one that was opened by the event triggered in OnExecute code (as above). What is wrong with it ? – JRG Sep 19 '17 at 20:01
  • _but it only returns the caller form_ It depends on how you are calling it. and please don't tell me it is from a button click in your form principal – Nasreddine Galfout Sep 19 '17 at 20:49
  • see these: [delphi-capturing-the-window-form-which-has-current-focus](https://stackoverflow.com/questions/6495824/delphi-capturing-the-window-form-which-has-current-focus) // [how-to-get-the-currently-active-form-in-my-application](https://stackoverflow.com/questions/29846548/how-to-get-the-currently-active-form-in-my-application) – Nasreddine Galfout Sep 19 '17 at 20:50
  • I checked and implemented [Delphi - Capturing the Window/Form which has current focus] , this code led to an exception just after close the application. I'm not using MDI and the code seems to be adressed for MDI programs. – JRG Sep 19 '17 at 22:04
  • At this moment, to understand the mechanism of caller/called form I put the call in a Button, but as soon as I understand how that works, I'll code it in a TAction and use Tmenu. is there any restriction to call from a button ? – JRG Sep 19 '17 at 22:08
  • @JRG the problem is not in the `ActiveForm` property it is in the way you call it, because your `formbanco` parent is the panel which parent is the `formprincipal` then the active form is `formprincipal` because it has no parent `parent = nil`. In other words the design you use will never return `formbanco` as the active form – Nasreddine Galfout Sep 19 '17 at 22:22
  • @JRG `Formbanco.Parent := PanelCorpo;` remove this line and you will have your desired output – Nasreddine Galfout Sep 19 '17 at 22:55
  • I'm change the code and try to understande what is going on. It seems you're right regardind the Parent PanelCorp. I remove it and now Screen.ActiveForm.Name is working perfectly. Please wait my final tests and I'll back to you. Thanks. – JRG Sep 19 '17 at 23:48
  • Nasreddine, I finally understood now (I hope so) : A) you were right regarding the behaviour of Screen.ActiveForm.Name return always FormPrincipal due to Formbanco Parent is a PanelCorpo that belongs to FormPrincipal B) When use Form.Show , it does not run OnActivate event, I don't know why. So I had to put a line code Formbanco.OnActivate after Formbanco.Show. C) Before to Create/Open a new Form I run a procedure to check if it is already created and if so, I run FreeAndNil(Formvariable). I'll update my final code in the question. I appreciate your comment on that. Thanks a lot! – JRG Sep 20 '17 at 03:11