1

i have 2 Form (Form1 and Form2) in the my project, Form1 is Auto-create forms, but Form2 is Available forms. how i can to create Form2 and unload Form1?

I received a "Access validation" Error in this code.

Here is Form1 code:

1.  uses Unit2;
//*********
2.  procedure TForm1.FormCreate(Sender: TObject);
3.  var a:TForm2;
4.  begin
5.      a := TForm2.Create(self);
6.      a.Show;
7.      self.free;  // Or self.destory;
8.  end;

Thanks.


I modified that "Serg" code to this :

unit Unit1;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, StdCtrls;

type
  TForm1 = class(TForm)
    Button1: TButton;
    procedure Button1Click(Sender: TObject);
  private
    { Private declarations }
  public
    { Public declarations }
  end;
var
  Form1: TForm1;

implementation

uses Unit2;

{$R *.dfm}

procedure TForm1.Button1Click(Sender: TObject);
begin
  Application.CreateForm(TForm2, Form2);
  Release;
end;

end.

///

program Project1;
uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};
{$R *.res}
begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Form1:= TForm1.Create(Application);
  Application.Run;
end.

but this project start and then exit automatically, Why? i want to show Form1 and when we click Button1 then show Form2 and free(Release) Form1. how i can to this?

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
return
  • 1,049
  • 5
  • 17
  • 27

5 Answers5

13

When you destroy a form, it's better to use Release.

Release is almost the same as free, but it waits for pending messages to avoid crashes.

You should never use Destroy. Free/Release calls the destructor.

Self is the current object (in your code Form1, so self.Free kills the current form. Which results in the access violation. Form1 is auto created, it is also auto destroyed so you shouldn't destroy it yourself. If you don't want it, hide it.

And you should keep a reference to the newly created form if you want to handle it later.

Your modified code should be like:

uses Unit2;

TForm1 = class (TForm)
private
  FChild : TForm2;
end;

procedure TForm1.FormCreate(Sender: TObject);
begin
  FChild := TForm2.Create(nil);
  Hide; // Hides form 1
  FChild.Show;
end;

procedure TForm2.FormDestroy(Sender: TObject);
begin
  FChild.Release;
end;

But Why do you want to create another form in the form create of the first form. Why not remove the first form entirely and only use the second one (auto created)?

Toon Krijthe
  • 52,876
  • 38
  • 145
  • 202
  • Thank you Gamecat. In the my project i have many forms.form1 is a form for set some configuration when my application started.I want to show form1 and when user set that configuration, then unload form1 and show form2. you have any better idea? – return Jan 07 '11 at 08:25
  • when i use your modified code,Form1 visible for about 1 second and then hide. why? (i want to invisible form1 completely) – return Jan 07 '11 at 13:38
  • @User, that's going to bite you later. The first auto-created form is designated the *main form*, and when the main form is destroyed, the application terminates, even if there are other forms still present. Do this instead: In your DPR file, create and show the config form with `Form1 := TForm1.Create(nil); Form1.ShowModal; Form1.Free;` After that, let Form2 be auto-created with the usual `Application.CreateForm(Form2, TForm2)`. For a more detailed response, post a new question, such as "How can I display a configuration form before the main form?" – Rob Kennedy Jan 07 '11 at 14:33
  • Not using that Release in place of Free has caused me a migraine. Never knew this all important piece of advice. – user30478 Jan 02 '19 at 02:05
  • beware that as today Release() is deprecated – lluca Mar 31 '20 at 18:48
2

You are trying to do something strange.

You cannot free main form without closing application, so your Form1 should not be autocreated form, both Form1 and Form2 should be created manually.

First, you should edit your project source like this to create Form1 manually:

program Project9;

uses
  Forms,
  Unit1 in 'Unit1.pas' {Form1},
  Unit2 in 'Unit2.pas' {Form2};

{$R *.res}

begin
  Application.Initialize;
  Application.MainFormOnTaskbar := True;
  Form1:= TForm1.Create(Application);
  Application.Run;
end.

Form1.OnCreate should be written as

procedure TForm1.FormCreate(Sender: TObject);
begin
  Application.CreateForm(TForm2, Form2);
  Release;
end;

that will make Form2 the main form of your application. As already answered you should use Release method to free the form.

kludg
  • 27,213
  • 5
  • 67
  • 118
  • Thanks for reply.if i want to add a button to Form1 and type Application.CreateForm(TForm2, Form2); Release; in it, i must modified code to ???? (if i put this code in button application start and then exit) – return Jan 07 '11 at 13:40
  • 1
    @user482923: if you have more questions please ask them as new questions, with detailed description and code, not as comments. It is difficult to understand and answer the questions in comments. – kludg Jan 07 '11 at 14:07
0
begin
  Application.Initialize;
  Application.CreateForm(TForm1, Form1);
  Application.Run;
end.

...

procedure TForm1.FormClose(Sender: TObject; var CanClose: Boolean);
begin
  if MessageDlg ('Are you want to exit?', mtConfirmation,
      [mbYes, mbNo], 0) = mrNo then
    CanClose := False;
end;

So, that is all...

tbutton
  • 111
  • 6
0

If all Form1 should do is initialize something but not being shown, consider using a datamodule instead. These cannot be shown but can still be autocreated.

dummzeuch
  • 10,975
  • 4
  • 51
  • 158
0

If Form1 is 'autocreate', it's owned by the application object - you shouldn't free it in your code. If Form1 owns Form2, application cleans up both.

I'd do it like this, but not sure it meets your requirements:

procedure TForm1.FormCreate(Sender: TObject);
var a:TForm2;
begin
  a := TForm2.Create(nil);
  try
    a.Show;
 finally
   freeandNil(a);
 end; 
end;
Vector
  • 10,879
  • 12
  • 61
  • 101
  • The form will be shown and then immediately destroyed, which leaves no time for interaction – mjn Jun 13 '11 at 10:39
  • Shouldn't that be Free not FreeAndNil? –  Apr 27 '12 at 19:04
  • Of course mjn is correct. If you are showing non-modal then freeing immediately will be pretty useless. In that case, you should decide what you want to do with your form in the TForm.OnClose event: TForm1.FormClose(Sender: TObject; var Action: TCloseAction); TCloseAction is an enumeration with 4 members: (caNone, caHide, caFree, caMinimize); Set the Action variable that's passed into the event to the behavior you need. – Vector Apr 27 '12 at 21:25
  • My mistake then, I've never seen a reason to use FreeAndNil, always .Free; –  Apr 28 '12 at 13:50
  • True - in many contexts it's not really necessary- good code should never really have use for it. I just do it out of habit and because I'm naturally paranoid LOL. Although one could argue that it's using extra processor cycles, I seriously doubt if in our modern evnironments that has any significance. – Vector Apr 30 '12 at 14:52