Solved

How to capture a MDIChild close event in the parent

Posted on 2002-04-16
18
664 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
[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
  • 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
Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
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

[Webinar] How Hackers Steal Your Credentials

Do You Know How Hackers Steal Your Credentials? Join us and Skyport Systems to learn how hackers steal your credentials and why Active Directory must be secure to stop them. Thursday, July 13, 2017 10:00 A.M. PDT

Question has a verified solution.

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

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…
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…
There are cases when e.g. an IT administrator wants to have full access and view into selected mailboxes on Exchange server, directly from his own email account in Outlook or Outlook Web Access. This proves useful when for example administrator want…
If you’ve ever visited a web page and noticed a cool font that you really liked the look of, but couldn’t figure out which font it was so that you could use it for your own work, then this video is for you! In this Micro Tutorial, you'll learn yo…
Suggested Courses
Course of the Month10 days, 7 hours left to enroll

628 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