Solved

How to capture a MDIChild close event in the parent

Posted on 2002-04-16
18
654 Views
Last Modified: 2010-08-05
I try to trigger some procedure in MDI application parent from when a MDI child closed.

Thanks.
0
Comment
Question by:jlislo
  • 8
  • 5
  • 3
  • +1
18 Comments
 
LVL 17

Expert Comment

by:inthe
ID: 6945415
have you tried:

uses form1;

on form2(mdichild).close event;

form1.myprocedure;
0
 

Author Comment

by:jlislo
ID: 6945506
Not yet.

Which event on the main form you will place the "on form2(mdichild).close event;"

Question is which main form even got trigger when the child close.

Thanks.
0
 
LVL 17

Expert Comment

by:inthe
ID: 6945548
No no i mean use the child forms close event.

on its close event you could call your main forms procedure

form1.myprocedure;
or
form1.button2.click;
0
Free Tool: Site Down Detector

Helpful to verify reports of your own downtime, or to double check a downed website you are trying to access.

One of a set of tools we are providing to everyone as a way of saying thank you for being a part of the community.

 
LVL 2

Expert Comment

by:freshman3k
ID: 6945573
Hello!

Just in case you need more events there are
Follow should work:
private
    { Private declarations }
    FClientInstance : TFarProc;
    FPrevClientProc : TFarProc;
    procedure ClientWndProc(var aMessage: TMessage);


implementation

procedure TfrmMForm.FormShow(Sender: TObject);
begin
   FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
   FClientInstance := MakeObjectInstance(ClientWndProc);
   SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));
end;

procedure TfrmMForm.ClientWndProc(var aMessage: TMessage);

   procedure DoDefault;
   begin
      with aMessage do
        Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam,
lParam);
   end;

begin
   with aMessage do
     case Msg of
         WM_MDICREATE:
           begin
             {this event is when an application wants to create a child window}
              {put your procedure here}
             DoDefault;
           end;
         WM_MDIDESTROY:
           begin
            {this event is when when an MDI Child is closed.So this event is what you need
            {put your procedure here}
              DoDefault;
           end;
         WM_MDIACTIVATE:
           begin
              DoDefault;
            {this event is when a new MDI child window is activated  
            {put your procedure here}
           end;
         WM_MDINEXT:
           begin
              DoDefault;
            {this event is when a next or previous child window is activated }
            {put your procedure here}
           end;
         else
           DoDefault;
     end;
end;

Good Luck!
0
 
LVL 2

Expert Comment

by:freshman3k
ID: 6945580
Hello!

Just in case you need more events there are
Follow should work:
private
    { Private declarations }
    FClientInstance : TFarProc;
    FPrevClientProc : TFarProc;
    procedure ClientWndProc(var aMessage: TMessage);


implementation

procedure TfrmMForm.FormShow(Sender: TObject);
begin
   FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
   FClientInstance := MakeObjectInstance(ClientWndProc);
   SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));
end;

procedure TfrmMForm.ClientWndProc(var aMessage: TMessage);

   procedure DoDefault;
   begin
      with aMessage do
        Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam,
lParam);
   end;

begin
   with aMessage do
     case Msg of
         WM_MDICREATE:
           begin
             {this event is when an application wants to create a child window}
              {put your procedure here}
             DoDefault;
           end;
         WM_MDIDESTROY:
           begin
            {this event is when when an MDI Child is closed.So this event is what you need
            {put your procedure here}
              DoDefault;
           end;
         WM_MDIACTIVATE:
           begin
              DoDefault;
            {this event is when a new MDI child window is activated  
            {put your procedure here}
           end;
         WM_MDINEXT:
           begin
              DoDefault;
            {this event is when a next or previous child window is activated }
            {put your procedure here}
           end;
         else
           DoDefault;
     end;
end;

Good Luck!
0
 

Author Comment

by:jlislo
ID: 6945594
For inthe:

If I call the main form in MDIChild.onClose event, the MDIChildCount still count the one is closing. I like to use main form's event if possible. Thanks.

For freshman3k
I will try this. Thanks.
0
 

Author Comment

by:jlislo
ID: 6945718
For freshman3k

question, where did you place the following code?

begin
  with aMessage do
    ...
  end ;
end;

Thanks.
0
 

Author Comment

by:jlislo
ID: 6945720
For freshman3k

Sorry never mind, I didn't read through your code. Let me try this. Thanks.
0
 

Author Comment

by:jlislo
ID: 6945732
For freshman3k

Why MDIChildCount still = 1 after  WM_MDIDESTROY?

Did I need to do Application.Processmessage to get a correct MDIChildCount ?

Thanks.

Jammy
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6945798
listening . . .
i would done it like barry . . .

call a mainform-procedure you have coded there in the onclose or ondestroy-event of the childform

why do you need an event?
you can call a notify-procedure
from your coded mainform-procedure,
if you need an on...-event

the notify-procedure
you must code also byself

meikl ;-)
0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6945803
or you could just send a wm_user+xx message to the mainform,
and code a message-handler in your mainform
... just as third suggestion

meikl ;-)
0
 

Author Comment

by:jlislo
ID: 6945818
Hi meikl,

I need to know when a child is create/destroy/active/deactive so I can adjest my main form menu items. Call main from from child does not give me a correct child count. (child.OnClose) What is your thought of the correct way to do this?

Thanks.

Jammy
0
 
LVL 2

Expert Comment

by:freshman3k
ID: 6945850
Hello!

Try this code ,this time it has only what you want and some changes:

private
   { Private declarations }
   FClientInstance : TFarProc;
   FPrevClientProc : TFarProc;
   procedure ClientWndProc(var aMessage: TMessage);

implementation

procedure TfrmMForm.FormShow(Sender: TObject);
begin
  FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
  FClientInstance := MakeObjectInstance(ClientWndProc);
  SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));
end;

procedure TfrmMForm.FormClose(Sender: TObject);
begin
 SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FPrevClientProc));
end;

procedure TfrmMForm.ClientWndProc(var aMessage: TMessage);
begin
  with aMessage do
    case Msg of
      WM_MDIDESTROY:
          begin
           {put your procedure here}
             aMessage.Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam,lParam);
          end;
    else
      aMessage.Result := CallWindowProc(FPrevClientProc, ClientHandle, Msg, wParam,lParam);  
    end;
end;


0
 
LVL 27

Expert Comment

by:kretzschmar
ID: 6945979
>does not give me a correct child count
?
as you now in any way that the child will be closed,
why not decrement the childcount by one,where you do need it
or
you could provide the childform itself as parameter, if needed
like
MainformChildCloseInformationProc(self);
and use this as reference instead of the childcount

i guess also freshmans suggestion will not give you
the right childcount, as the proc is called before the childform is destroyed

meikl ;-)

0
 
LVL 2

Expert Comment

by:freshman3k
ID: 6946009
Hello!

Oh now I understand,Here is the modified code(I didnt try it yet):

private
  { Private declarations }
  FClientInstance : TFarProc;
  FPrevClientProc : TFarProc;
  CC : Integer;
  procedure ClientWndProc(var aMessage: TMessage);

implementation

procedure TfrmMForm.FormShow(Sender: TObject);
begin
 FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
 FClientInstance := MakeObjectInstance(ClientWndProc);
 SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));
end;

procedure TfrmMForm.FormClose(Sender: TObject);
begin
SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FPrevClientProc));
end;

procedure TfrmMForm.ClientWndProc(var aMessage: TMessage);
 
 procedure DoDefault;
  begin
     with aMessage do
       Result := CallWindowProc(FPrevClientProc,ClientHandle, Msg, wParam,lParam);
  end;

begin
 with aMessage do
   case Msg of
     WM_MDIDESTROY:
         begin
           CC:=CC-1;
           {put your procedure here}
           DoDefault;
         end;
     WM_MDICREATE:
         begin
           CC:=CC+1;
           {put your procedure here}
           DoDefault;
         end;
   else
     DoDefault;  
   end;
end;

And now the varible CC contains the childcount

Good Luck!
0
 
LVL 2

Accepted Solution

by:
freshman3k earned 50 total points
ID: 6946024
Hello!

Oh now I understand,Here is the modified code(I didnt try it yet):

private
  { Private declarations }
  FClientInstance : TFarProc;
  FPrevClientProc : TFarProc;
  CC : Integer;
  procedure ClientWndProc(var aMessage: TMessage);

implementation

procedure TfrmMForm.FormShow(Sender: TObject);
begin
 FPrevClientProc := Pointer(GetWindowLong(ClientHandle, GWL_WNDPROC));
 FClientInstance := MakeObjectInstance(ClientWndProc);
 SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FClientInstance));
end;

procedure TfrmMForm.FormClose(Sender: TObject);
begin
SetWindowLong(ClientHandle, GWL_WNDPROC, LongInt(FPrevClientProc));
end;

procedure TfrmMForm.ClientWndProc(var aMessage: TMessage);
 
 procedure DoDefault;
  begin
     with aMessage do
       Result := CallWindowProc(FPrevClientProc,ClientHandle, Msg, wParam,lParam);
  end;

begin
 with aMessage do
   case Msg of
     WM_MDIDESTROY:
         begin
           CC:=CC-1;
           {put your procedure here}
           DoDefault;
         end;
     WM_MDICREATE:
         begin
           CC:=CC+1;
           {put your procedure here}
           DoDefault;
         end;
   else
     DoDefault;  
   end;
end;

And now the varible CC contains the childcount

Good Luck!
0
 

Author Comment

by:jlislo
ID: 6946105
meikl,

"why not decrement the childcount by one,where you do need it"

I understand if I decrement one I will get to correct number, but why? Is something wrong in MDIChildcount?


freshman3k,

If I add MessageDlg into your code like this

    WM_MDIDESTROY:
        begin
          CC:=CC-1;
          {put your procedure here}
          DoDefault;
          MessageDlg('C:'+inttostr(MDIChildCount), mtInformation, [mbOK], 0);
 
        end;

I will return to correct number but when you close the last child it loop here twice (second time give me the correct number)

But if I put some other procedure here it loop onece and I need to dec the count.

Thank you both very much, if no comment add, I will accept freshman3k's answer.


0
 

Author Comment

by:jlislo
ID: 6946132
Thank you very much!
0

Featured Post

Networking for the Cloud Era

Join Microsoft and Riverbed for a discussion and demonstration of enhancements to SteelConnect:
-One-click orchestration and cloud connectivity in Azure environments
-Tight integration of SD-WAN and WAN optimization capabilities
-Scalability and resiliency equal to a data center

Question has a verified solution.

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

Suggested Solutions

Title # Comments Views Activity
Downloading email attachments 2 80
Multiple image collision 13 80
update joined tables 2 55
How to save the image in the .cds File ClientDataSet? 1 22
A lot of questions regard threads in Delphi.   One of the more specific questions is how to show progress of the thread.   Updating a progressbar from inside a thread is a mistake. A solution to this would be to send a synchronized message to the…
Introduction I have seen many questions in this Delphi topic area where queries in threads are needed or suggested. I know bumped into a similar need. This article will address some of the concepts when dealing with a multithreaded delphi database…
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …
This video shows how to use Hyena, from SystemTools Software, to bulk import 100 user accounts from an external text file. View in 1080p for best video quality.

828 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