?
Solved

Delphi closing all forms

Posted on 2003-03-10
12
Medium Priority
?
4,101 Views
Last Modified: 2007-12-19
Please help,

I am trying to close all mdi froms inside a main form (except the main form)
with the following code:

////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
Procedure TmainForm.CloseAllForms;
var
 CIndex: Integer;
 FIndex: Integer;
begin
  With MainForm do
  for fIndex := MdiChildCount - 1 downto 0 do
  begin
    for CIndex := 0 to MDIChildren[fIndex].ComponentCount - 1 do
    begin
      if ((MDIChildren[fIndex].Components[CIndex] is TQuery) or
          (MDIChildren[fIndex].Components[CIndex] is TTable)) then
      begin
        if TTable(MDIChildren[fIndex].Components[CIndex]).State in [dsEdit,
dsInsert]  then
        try
          TTable(MDIChildren[fIndex].Components[CIndex]).Cancel;
        except
        end;
      end;
    end;
    MDIChildren[fIndex].Close;
  end;

  // i need the below code because sometimes the main form is disabled and i
cannot do anything on it
  application.MainForm.formstyle := fsNormal;
  application.ProcessMessages;
  application.MainForm.formstyle := fsMDIForm;
  application.ProcessMessages;
end;
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
The mdi forms are created by looping through all forms on screen (i.e.
screen.formcount)
and if the form is found (by checking its class) it calls bringtofront to
show the form it else it creates it;
on the OnClose event of all mdi forms there is an Action := caFree;


The mdi forms may have modal forms which are called as follows:
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////
var
    Form: tfrmmyform;
begin
  Form := tfrmmyform.Create(Self);
  try
    form.showmodal;
  finally
    form.free;
  end;
end;
////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////////////////////////////////////////

The problem is:
1) When I try to reopen the mdi-form again (which was previously closed by
the MDIChildren[fIndex].Close), the form is not shown
     as it is still found on the Screen.Forms, and when bringtofront is
called nothing happens.
2)  When I close the main form (no mdi forms on screen - just the main form)
the code passes to the finally part of the modal form,
      causing an access violation.


Please help urgently.  if you need more information pls tell

Regards
Joseph Pellicano

0
Comment
Question by:pellj001
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 6
  • 5
12 Comments
 
LVL 9

Expert Comment

by:mocarts
ID: 8101674
first, you may want to alter this code to work only with TDataSet (or instead place it in OnClose event of MIDChild). (if component is TQuery you may get AccessViolation as it is not the same as TTable):
...
for CIndex := 0 to MDIChildren[fIndex].ComponentCount - 1 do
begin
  if ((MDIChildren[fIndex].Components[CIndex] is TDataSet) then
  begin
    if TDataSet(MDIChildren[fIndex].Components[CIndex]).State in [dsEdit,
dsInsert]  then
      try
        TDataSet(MDIChildren[fIndex].Components[CIndex]).Cancel;
      except
      end;
  end;
end;

from which place (form, subform, modal or not) you call that CloseAllForms method?
mo.
0
 

Author Comment

by:pellj001
ID: 8101759
I am calling the CloseAllForms from the main form (on a timer event)

Joseph Pellicano
0
 
LVL 9

Expert Comment

by:mocarts
ID: 8101931
to show mdichildren modal you set form style to fsNormal? in this case form will not be in MDIChildren collection.

you may use this code to close all forms except main:

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: integer;
begin
  for i := Screen.FormCount -1 downto 0 do
  begin
    if Screen.Forms[i] <> Self then
      Screen.Forms[i].Close;
  end;
end;

mo.
0
VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

 
LVL 9

Expert Comment

by:mocarts
ID: 8101935
TForm1 in my case is TmainForm in your case.
0
 

Author Comment

by:pellj001
ID: 8101978
Mdi modal forms are all set to fsNormal
While mdi non modal forms are set to fsMdiChild
TMainForm is set to fsMdiForm

When you call Screen.Forms[i].close the form in question is not freed.  If you check screen.form count after calling Screen.Forms[i].close the result will be the same.

Also when calling Screen.Forms[i].close for a mdi-form the code passes through the formclose event of that form.  However when calling Screen.Forms[i].close for a modal form the code does not pass from the formclose event.

My problem still applies.

0
 
LVL 9

Expert Comment

by:mocarts
ID: 8102070
to trigger OnClose event for modal form you should set ModalResult to some value other than zero:

procedure TForm1.Timer1Timer(Sender: TObject);
var
 i: integer;
begin
 Timer1.Enabled := FAlse;
 for i := Screen.FormCount -1 downto 0 do
 begin
   if Screen.Forms[i] <> Self then
     if fsModal in Screen.Forms[i].FormState then
       Screen.Forms[i].ModalResult := mrCancel
     else
       Screen.Forms[i].Close;
 end;
  Application.ProcessMessages;
  ShowMessage(inttostr(Screen.FormCount));
end;

and form count will be 1 only after modal form freeing:

procedure TForm1.Button2Click(Sender: TObject);
begin
  with TForm2.Create(Self) do
  try
    ShowModal;
  finally
    Free;
  end;
  ShowMessage(inttostr(Screen.FormCount));
end;

0
 

Expert Comment

by:serak
ID: 8104826
Hi, I had the same problem until I included this!

1. In every MdiChild.Close event include these two lines:

  Action := caFree;
  Release;

2. And in your MainForm you want to include this Notification:

TfrmMain = class(TForm)
  private
    procedure Notification(AComponent:TComponent; Operation:TOperation);override;
  end;

procedure TfrmMain.Notification(AComponent:TComponent; Operation:TOperation);
begin
  inherited Notification(AComponent, Operation);
  if (Operation=opRemove) then begin
    // If you have control of the subforms:
    if      (AComponent=frmSub1) then frmSub1:=Nil
    else if (AComponent=frmSub2) then frmSub2:=Nil
    ...
    //OR this one:
    AComponent:=Nil;
  end;
end;

This should clean things up.
0
 

Author Comment

by:pellj001
ID: 8109670
to serak;
Can you give me the code for the closing of all forms.
I am still receiving access violations.

Joseph
0
 
LVL 9

Expert Comment

by:mocarts
ID: 8109898
if you use Release then you must call AddRef before ShowModal or don't use Free, as Release, if reference counter is zero, frees form.
Can you tell us, Joseph, what you exactly want to do with your app. why this onTimer event closing all forms?
mo.
0
 

Author Comment

by:pellj001
ID: 8110345
I tell you what am I trying to do.
I have a mainform (fsMdiForm) from which mdiChild forms can be called from the main menu.  An mdiChild may call other modal forms.

When a specified timer is reached, I am loading a form so that the user logs on again.  After he logs on, if the user is not the same I am closing (or trying to close) all the forms on the main form.

mo, I did not understand your last comment.  I do not know what Addref is?

Joseph
0
 
LVL 9

Accepted Solution

by:
mocarts earned 1000 total points
ID: 8110470
Sorry, I mixed Release with _Release which takes care of reference counting..

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: integer;
begin
  Timer1.Enabled := False;
  with TfrmLogin.Create(self) do
  try
    ShowModal;
    BringToFront; // to front of other modal form if any

    if not LoginOk then // login filed (LoginOk property of TfrmLogin)
    // close all forms (if loginOk we can leave forms opened)
    for i := Screen.FormCount -1 downto 0 do
    begin
      if Screen.Forms[i] <> Self then
        if fsModal in Screen.Forms[i].FormState then
          Screen.Forms[i].ModalResult := mrCancel
        else
          Screen.Forms[i].Close;
    end;
  finally
    free;
  end;
end;

and your main problem - when showing your form modal create form with no owner:

var
   Form: tfrmmyform;
begin
 Form := tfrmmyform.Create(nil); // to turn off auto freeing by owner
 try
   form.showmodal;
 finally
   form.free;
 end;
end;

wbr, mo.
0
 

Author Comment

by:pellj001
ID: 8117720
that create(nil) seemed to solve my problem.

Thank you very much mocarts.
0

Featured Post

VIDEO: THE CONCERTO CLOUD FOR HEALTHCARE

Modern healthcare requires a modern cloud. View this brief video to understand how the Concerto Cloud for Healthcare can help your organization.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

This article explains how to create forms/units independent of other forms/units object names in a delphi project. Have you ever created a form for user input in a Delphi project and then had the need to have that same form in a other Delphi proj…
Creating an auto free TStringList The TStringList is a basic and frequently used object in Delphi. On many occasions, you may want to create a temporary list, process some items in the list and be done with the list. In such cases, you have to…
In this brief tutorial Pawel from AdRem Software explains how you can quickly find out which services are running on your network, or what are the IP addresses of servers responsible for each service. Software used is freeware NetCrunch Tools (https…
Sometimes it takes a new vantage point, apart from our everyday security practices, to truly see our Active Directory (AD) vulnerabilities. We get used to implementing the same techniques and checking the same areas for a breach. This pattern can re…
Suggested Courses
Course of the Month14 days, 22 hours left to enroll

771 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question