Want to protect your cyber security and still get fast solutions? Ask a secure question today.Go Premium

x
  • Status: Solved
  • Priority: Medium
  • Security: Public
  • Views: 681
  • Last Modified:

How to capture a MDIChild close event in the parent

I try to trigger some procedure in MDI application parent from when a MDI child closed.

Thanks.
0
jlislo
Asked:
jlislo
  • 8
  • 5
  • 3
  • +1
1 Solution
 
intheCommented:
have you tried:

uses form1;

on form2(mdichild).close event;

form1.myprocedure;
0
 
jlisloAuthor Commented:
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
 
intheCommented:
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
Concerto's Cloud Advisory Services

Want to avoid the missteps to gaining all the benefits of the cloud? Learn more about the different assessment options from our Cloud Advisory team.

 
freshman3kCommented:
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
 
freshman3kCommented:
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
 
jlisloAuthor Commented:
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
 
jlisloAuthor Commented:
For freshman3k

question, where did you place the following code?

begin
  with aMessage do
    ...
  end ;
end;

Thanks.
0
 
jlisloAuthor Commented:
For freshman3k

Sorry never mind, I didn't read through your code. Let me try this. Thanks.
0
 
jlisloAuthor Commented:
For freshman3k

Why MDIChildCount still = 1 after  WM_MDIDESTROY?

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

Thanks.

Jammy
0
 
kretzschmarCommented:
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
 
kretzschmarCommented:
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
 
jlisloAuthor Commented:
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
 
freshman3kCommented:
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
 
kretzschmarCommented:
>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
 
freshman3kCommented:
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
 
freshman3kCommented:
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
 
jlisloAuthor Commented:
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
 
jlisloAuthor Commented:
Thank you very much!
0

Featured Post

What does it mean to be "Always On"?

Is your cloud always on? With an Always On cloud you won't have to worry about downtime for maintenance or software application code updates, ensuring that your bottom line isn't affected.

  • 8
  • 5
  • 3
  • +1
Tackle projects and never again get stuck behind a technical roadblock.
Join Now