3
votes

I'm looking to prevent MDI child WindowState changes occurring when creating a second MDI child...

I have an application that I'm developing, written in Delphi. Through a little Delphi/Windows magic, the application has multiple MDI Parents and multiple MDI Children.

I can create a form (Child A1), and maximize it within an MDI parent (Parent A). I can create a second form (Child B1) and maximize it within a second MDI parent (Parent B). Both forms will be mazimized in seperate MDI parents. So far so good. I've got this working.

However, when I create a second MDI child (Child A2) in the first MDI parent (Parent A) the WindowState (wsMaximized) of the first child (Child A1) changes when the second child (Child A2) is created. I want the first child (Child A1) to remain maximized, and the second child (Child A2) to be created and placed on top of the first child...

How can I prevent the state of the first MDI Child changing but also create a second MDI child? Any hints?

OK - Now I've had some lunch maybe I can explain it better... here's a second go at it...

The behaviour described can be reproduced in a simple MDI application (the magic I have used to create multiple MDI parents doesn't impact my problem)

Create a new forms application changing formstyle to fsMdiForm Create a second form change its style to fsMDIChild Create a third form change its style to fsMDIChild

Run the app. Instantiate the second form, then maximize (works as expected - maximizes in MDI Parent) Instantiate the third form, the third form opens with window state wsNormal. But when the third form is created, the window state of the second form changes - it ceases to be maximized, and becomes wsNormal, as if you had clicked restore!

I want to avoid the restoring of the second form when I open the third form... (All forms have an initial WindowState of wsNormal...

Any hints greatly appreciated!

3
Windows (and Delphi) don't support multiple MDI parents in a single application. It defeats the whole design of MDI. If you're somehow getting more than one MDI parent, it's no longer an MDI application and the behavior is IMO totally unpredictable.Ken White
"Through a little Delphi/Windows magic" Do we need to know what this magic is in order to help?David Heffernan
The normal behaviour of Windows/MDI-childs is, that they all have the same state when maximized or normal. Make one MDI-child maximized and all others are maximized also and vice versa. That is windows standard.Andreas
@Andreas That's not what 0909EM is saying. Apparently creating the second MDI child form changes the window state of the first child. The second MDI child should be created maximised. That's what I saw when I tried to replicate the issue.David Heffernan
Are you sure your "magic" isn't involved? I can imagine that maybe the magic required you to change the VCL source so that MDI children aren't quite so tied together, which causes the new form not to acquire the state of the existing form (since it might have a different parent), but since it required changing the VCL, you're unknowingly creating "magic" programs even when you think you're making a plain, stock test program.Rob Kennedy

3 Answers

1
votes

In my application, I also use multiple MDI Parents. Below is my magic code, where the different Childs have different states, in each Parent.

This code is adopted from: ID: 23574, Multiple MDI Parent Forms in a single Application

//Add multiple MDIForm support
TFormMDIEnhance = class(TForm)
  private
    _mdiClientHandle: HWND;
    function GetMDIClientHandle: HWND;
  protected
    procedure CreateWindowHandle(const Params: TCreateParams); override;
    procedure DestroyWindowHandle; override;
  end;

procedure TFormMDIEnhance.CreateWindowHandle(const Params: TCreateParams);
var
  mdiStruct: MDICREATESTRUCT;
begin
  _mdiClientHandle := GetMDIClientHandle;

  if (FormStyle = fsMDIChild) then
  begin
    mdiStruct.szClass := Params.WinClassName;
    mdiStruct.szTitle := Params.Caption;
    mdiStruct.hOwner := HInstance;
    mdiStruct.x := Params.X;
    mdiStruct.y := Params.Y;
    mdiStruct.cx := Params.Width;
    mdiStruct.cy := Params.Height;
    mdiStruct.style := Params.Style;
    mdiStruct.lParam := LPARAM(Params.Param);

    WindowHandle := SendStructMessage(_mdiClientHandle, WM_MDICREATE, 0, mdiStruct);
    Include(FFormState, fsCreatedMDIChild);
  end
  else
    inherited CreateWindowHandle(Params);
end;

procedure TFormMDIEnhance.DestroyWindowHandle;
begin
  if fsCreatedMDIChild in FFormState then
    SendMessage(_mdiClientHandle, WM_MDIDESTROY, Handle, 0)
  else
    inherited DestroyWindowHandle;

  _mdiClientHandle := 0;
end;

function TFormMDIEnhance.GetMDIClientHandle: HWND;
var
  fm: TForm;
begin
  result := 0;

  if Owner is TForm then
  begin
    fm := Owner as TForm;
    if Assigned(fm) then
      Result := fm.ClientHandle;
  end;

  if (Result = 0) and Assigned(Application.MainForm) then
    Result := Application.MainForm.ClientHandle;

  if Result = 0 then
    raise EInvalidOperation.Create(SNoMDIForm);

end;

Inherit your forms from that Base form, then you can create multiple MDI Parents. Maybe that helps.

0
votes

It's taken me ages to work out what you are really asking but I think it boils down to this comment.

I want the WindowState behaviour of the MDI children to be different in a parent. So first MDI Child is wsMax'd and the second is wsNormal.

That's not possible in MDI. When an MDI child is maximized, that is the only child window that is visible.

0
votes

Remy and David are both correct in that it's an MDI limitation.

My solution in end, which does work, has been to maintain a ChildWindowState (which is just a WindowState) on each child form, then handling resizing/positioning of child windows when ChildWindowState changes... It's not a pretty answer but it does provide the functionality I needed in my application.

Thanks for all the answers :)