Using an if statement in Delphi 2006 to determine if a form exists

I have a form (frmNewStudentSelect) and would like to know how, within an if statement, to determine if the form exists.

LVL 4
wbstechAsked:
Who is Participating?
I wear a lot of hats...

"The solutions and answers provided on Experts Exchange have been extremely helpful to me over the last few years. I wear a lot of hats - Developer, Database Administrator, Help Desk, etc., so I know a lot of things but not a lot about one thing. Experts Exchange gives me answers from people who do know a lot about one thing, in a easy to use platform." -Todd S.

ziolkoCommented:
if Assigned(frmNewStudentSelect) then

ziolko.
0
ziolkoCommented:
what's important... use FreeAndNil() to dispose form when no longer needed
and :

procedure TForm1.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caFree;
end;

when form is MDI child

ziolko.
0
2266180Commented:
and something that never fails:

function formExists(form:TForm):boolean;
begin
  try
    if form.visible then;// just access a member. will through an AV if teh form does not exist
    result:=true;
  except
    result:=false;
  end;
end;

and use like
if formexists(frmNewStudentSelect) then
  blabla

this way you don't need to use freeandnil (though a good idea, I for example never used it :) so if you're in my case you'd like to use a method that doesn't rely on using it, until you get used to using it (this sounds "weird" :) ))
0
Python 3 Fundamentals

This course will teach participants about installing and configuring Python, syntax, importing, statements, types, strings, booleans, files, lists, tuples, comprehensions, functions, and classes.

diniludCommented:
ciuly your idea would't work.
try this and check.

First Button click will fine. What about second time


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 }
    function formExists(form:TForm):boolean;
  public
    { Public declarations }
  end;

var
  Form1: TForm1;
  x:TForm1;
implementation

{$R *.dfm}

function TForm1.formExists(form:TForm):boolean;
begin
  try
    if form.visible then;// just access a member. will through an AV if teh form does not exist
    result:=true;
  except
    result:=false;
  end;
end;


procedure TForm1.Button1Click(Sender: TObject);
begin
   if not formExists(X) then
         x:=TForm1.Create(Self);
   X.ShowModal;
   X.Free;
end;

end.
0

Experts Exchange Solution brought to you by

Your issues matter to us.

Facing a tech roadblock? Get the help and guidance you need from experienced professionals who care. Ask your question anytime, anywhere, with no hassle.

Start your 7-day free trial
ziolkoCommented:
why not this way?

procedure TForm1.Button1Click(Sender: TObject);
begin
   if not Assigned(X) then
         x := TForm2.Create(Self);
   X.ShowModal;
   FreeAndNil(x);
end;

ziolko.
0
2266180Commented:
dinilud: the example code works just fine. it's you that not payed attention :)
try debugging it. put a breakpoint on the if not formextss line and run teh application. first click, you step over with F8, you'll notice that X is created. second click, step over you'll notice that X is no longer created. the error you get is because you used showmodal and x is already showing modal so can't do that again ;)
0
2266180Commented:
also, I would like to make it clear if I didn't in my first post, that the *preffered* way is the one pointed out by ziolko. but not many are using it (me included :D )
0
ziolkoCommented:
to be more specific, i would do it this way:

procedure TForm1.Button1Click(Sender: TObject);
begin
  try
     if not Assigned(X) then
         x := TForm2.Create(Self);
     X.ShowModal;
   finally
     FreeAndNil(x);
   end;
end;

you never know whats gonna happen when you call ShowModal:)

ziolko.
0
diniludCommented:
Ciuly:

procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caHide;
end;

after exicuting this line,the memory must free and the pointer is not nil.
So Second time if you call your formExists function this will give false information.
(using watch window you can check)

i think your code will work only when pointer(means frmNewStudentSelect) is nil

ziolko:
Your Code will work perfectly when we use use ShowModel.
if you use show is it works fine?.
0
diniludCommented:
procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caHide;
  frmNewStudentSelect:=nil;
end;

.......

if not assigned(frmNewStudentSelect) then
  frmNewStudentSelect:=TfrmNewStudentSelect.create(self);

frmNewStudentSelect.show;
0
ziolkoCommented:
if you use Show instead ShowModal
it's your responsibility to make sure that reference to form will be set to nil

when you use exactly this code:

  try
     if not Assigned(X) then
         x := TForm2.Create(Self);
     X.Show;
   finally
     FreeAndNil(x);
   end;

you won't be able to even see form as it will be released immidietly after creating


ziolko
0
diniludCommented:
is my code is working?
0
ziolkoCommented:
never ever do this:

frmNewStudentSelect:=nil;

in event handler of frmNewStudentSelect

i think it will be a lot easier for us if you write what you trying achieve
hiding form is not same as releasing it

ziolko.





0
ziolkoCommented:
if you want only show/hide form in non-modal way simply go to project options and add it to autocreate section then use .Show .Hide

if you want create/destroy form use Assigned(), Create(), FreeAndNil() combination

ziolko.
0
diniludCommented:
if form is MDI Chid what we will do?.  MDIChild form we can't hide.
0
ziolkoCommented:
ahhh if it's MDI child then use:

procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
end;

and if you want check if it exists use

MDIParentForm.MDIChildCount
MDIParentForm.MDIChildren[i]

to browse thru all MDI children

ziolko.
0
diniludCommented:
ziolko.

procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
  frmNewStudentSelect:=nil;
  ShowMessage(Caption);
end;

This Code Shows Caption. Means Self is not released yet.
I think, The close event is generated by Self not frmNewStudentSelect.

So I think this code has no problem.

if my concept is wrong please Correct me. its my request to every body
0
2266180Commented:
dinilud: I have no idea why the code is not workign properly. it should. it is probably some "thing" in the borland implementation of the OO part, since once an object is freed, all memory associated with it should be freed as well, however, the object is still usable (partly). I'm guessing it has something to do with the COM layer, since all (?) delphi objects are also COM objects.


if you do the following:

  showmessage(inttostr(x.InstanceSize));
  x.free;
  showmessage(inttostr(x.InstanceSize));

you will see a very weird behaviour there, since the instance size after freeing will be a big (random?) number, in any case different than before freeing. so something happens along the way but I don't know what.

I think I'll open up a question to clarify this since I am curious why this happens :)
0
diniludCommented:
OK good idea for MDI Child. Thank you for your valuable information.
0
ziolkoCommented:
>>This Code Shows Caption. Means Self is not released yet.

nope form is not released yet in OnCloseEvent handler since this event is called as one of
routines during object destruction, but general rule is that assign nil after object is completely destroyed
(object not interface) from my exp. assignin nil to object within it's event handler will make some f*** up sooner or later

>>I think, The close event is generated by Self not frmNewStudentSelect.

I assume that frmNewStudentSelect is defined as
var frmNewStudentSelect: TfrmNewStudentSelect;
in same unit where whole def. of TfrmNewStudentSelect;
if so Self = frmNewStudentSelect
or maybe frmNewStudentSelect is declared somwhere else?

ziolko.
0
diniludCommented:
Ciuly:

  i know my language is very bad. Sorry for that.

    I don't no any thing aboult COM Layer.
    I think the form is freeing and memomory also relasing. But The object pointer is not setting nil.  
    So i think, if we try  to access that object again, program will assume the object is there because that pointer is not nil. So we get that random number as the instend size. I am also not sure is my concept is currect or not.
0
diniludCommented:
ziolko.


>>I assume that frmNewStudentSelect is defined as
>>var frmNewStudentSelect: TfrmNewStudentSelect;
>>in same unit where whole def. of TfrmNewStudentSelect;
>>if so Self = frmNewStudentSelect
>>or maybe frmNewStudentSelect is declared somwhere else?

Then i think in your compilier this also works!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree;
  frmNewStudentSelect:=nil;
  ShowMessage(Caption);
  ShowMessage(frmNewStudentSelect.Caption);
end;




0
diniludCommented:
ziolko.
   is my code is working?. if i hurt you i am asking you sorry. Once again i am telling I AM NOT EXPERT IN ENGLISH. I AM A PURE MALAYALEE( from KERALA).
0
ziolkoCommented:
heh dinilud no dramma mate i'm not hurt:)

but then can we go back to the point?
dinilud can you describe (dont worry about english:)) what are you exactly trying to do?

ziolko.
0
diniludCommented:

Through argument i am building my knowledge.
 i am not care about points.
i am also using your first way using showmodel. i tried to clarify my some doubt. thats all.
0
ziolkoCommented:
so no specific task or problem just trying to learn something new?

ziolko.
0
House_of_DexterCommented:
k...

procedure TfrmNewStudentSelect.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action:=caFree; //<-after this event fires...FormClose post a message back to Self to free
  frmNewStudentSelect:=nil; //this is fine...as long as you check if frmNewStudentSelect is assigned before calling it...
  ShowMessage(Caption);//no prob Self is still active and not freed yet
  ShowMessage(frmNewStudentSelect.Caption);//AcessViolation frmNewStudentSelect is nill
end;

k...lets understand Forms...

when you call Close this happens

procedure TCustomForm.Close;
var
  CloseAction: TCloseAction;
begin
  if fsModal in FFormState then
    ModalResult := mrCancel
  else
    if CloseQuery then
    begin
      if FormStyle = fsMDIChild then
        if biMinimize in BorderIcons then
          CloseAction := caMinimize else
          CloseAction := caNone
      else
        CloseAction := caHide;
      DoClose(CloseAction);//<----this is your FormClose
      if CloseAction <> caNone then
        if Application.MainForm = Self then Application.Terminate
        else if CloseAction = caHide then Hide
        else if CloseAction = caMinimize then WindowState := wsMinimized
        else Release;//<--this is the most important part...this is what happens when you set to caFree
    end;
end;

{your on FormClose which is called in  TCustomForm.Close
procedure TCustomForm.DoClose(var Action: TCloseAction);
begin
  if Assigned(FOnClose) then FOnClose(Self, Action);
end;
}

which calls

procedure TCustomForm.Release;
begin
  PostMessage(Handle, CM_RELEASE, 0, 0);
end;

which calls

procedure TCustomForm.CMRelease;
begin
  Free;
end;

the beauty of this is that any messages that are still in the the queue will be handled...meaning Self is still good until we get to CMRelease...



0
Wim ten BrinkSelf-employed developerCommented:
Can I suggest a much simp-ler solution? Why not walk through the Screen.CustomForms array and check if Screen.CustomForms[Index] is frmNewStudentSelect?

Something like:

function HasfrmNewStudentSelect: Boolean;
var I:Integer;
begin
  I := Pred(Screen.CustomFormCount);
  while (I > 0) and not Screen.CustomForms[I] is TfrmNewStudentSelect do Dec(I);
  Result := (I > 0);
end;

If your form is active, it will be listed in this array. Else it is not. :-)
0
swiatloCommented:
If you create all your forms with the same owner ie. MyForm.Create(Application). you could iterate through Application/Owner components to find out if it has it already.

result :=false
for i:=0 to ComponentCount-1 do
begin
  if MyOwner.Components[i].ClassName = 'TfrmNewStudentSelect' then
   {result:=true, break }
{
Or
  if MyOwner.Components[i].Name = 'frmNewStudentSelect' then result true, break }            
end
            
0
swiatloCommented:
Or simply
if MyOwner.Components[i] is TfrmNewStudentSelect then
  {result:=true, break }
0
Wim ten BrinkSelf-employed developerCommented:
swiatlo, your solution will work but is less reliable since it requires forms to be created with some owner. However, all forms will be part of the Screen.CustomForms list because they all add themselves to Screen.

Also, "MyOwner.Components[i].ClassName = 'TfrmNewStudentSelect'"... WTF??? You do realise that comparing strings in Delphi will be a lot slower than just checking the class type? :-)

Finally, while you can use for/break to walk through the list, in this case it's just better to use a while loop instead because the code tends to be slightly cleaner in the eyes of Pascal Puritanists. In general, things like label/goto/break/continue/exit are considered signs of bad programming by some developers, including me, because they make it less clear when a loop/procedure will exit.

One fix on my code, btw... This line:
Result := (I > 0);
should be replaced with:
Result := (Screen.CustomForms[I] is TfrmNewStudentSelect);
Or you should replace > with >=
0
bhavesh_joshiCommented:
if Assigned(frmNewStudentSelect) then ShowMessage('Created') else showmessage('Not created');

and if you want to know if its visible

if frmNewStudentSelect.visible then ShowMessage('Form is Visible') else showmessage('Form is InVisible')
0
bhavesh_joshiCommented:
if Assigned(frmNewStudentSelect) then ShowMessage('Created') else showmessage('Not created');

and if you want to know if its visible

if frmNewStudentSelect.visible then ShowMessage('Form is Visible') else showmessage('Form is InVisible')

or

if frmNewStudentSelect.Showing then ShowMessage('Form is Showing) else showmessage('Form is Hidden')
0
ziolkoCommented:
bhavesh_joshi all your comments were previously posted here

anyways wbstech i'm not pushig you but maybe it's time to close this Q?:)

ziolko.
0
It's more than this solution.Get answers and train to solve all your tech problems - anytime, anywhere.Try it for free Edge Out The Competitionfor your dream job with proven skills and certifications.Get started today Stand Outas the employee with proven skills.Start learning today for free Move Your Career Forwardwith certification training in the latest technologies.Start your trial today
Editors IDEs

From novice to tech pro — start learning today.