Controlling the placement of fsMDIChild windows in Delphi
Asked Answered
S

2

2

How do I control the placement of an MDI child window (FormStyle := fsMDIChild) in Delphi or C++Builder? I know that I can set Left, Top, Position, and so on, but for an MDI child in particular, these don't take effect until after the window has already been created and shown in its default location. The result is that creating and positioning several windows at once results in a fair bit of flicker as windows are created in their default positions then immediately moved and resized.

From delving into the VCL source, the only solution I've been able to find is to override TCustomForm's CreateParams method and change the X, Y, Width, and Height fields of the Params parameter, but that feels like a hack. Is there a cleaner way of doing this?

Suber answered 17/8, 2010 at 21:32 Comment(0)
N
1

I observe no flickering at all, but that might be because my computer is too fast or it might be an improvement in Windows 7 to reduce flickering.

I set the MDI child window position at its FormShow:

procedure TForm2.FormShow(Sender: TObject);
begin
  Top := 200;
  Left := 400;
end;
Nonconformist answered 17/8, 2010 at 21:37 Comment(1)
Thanks. I was trying to do it from the constructor and hadn't realized that OldCreateOrder was set to true. Once I fixed OldCreateOrder, using the constructor and FormShow both work.Suber
G
2

You can send WM_SETREDRAW messages to the MainForm's ClientHandle, one with the wParam set to False, and then later with the wParam set to True, to avoid flickering while you are setting up an MDI child window, eg:

Delphi:

SendMessage(Application.MainForm.ClientHandle, WM_SETREDRAW, False, 0);
try
  Child := TChildForm.Create(Self);
  Child.Left := ...;
  Child.Top := ...;
  Child.Show;
finally
  SendMessage(Application.MainForm.ClientHandle, WM_SETREDRAW, True, 0);
  InvalidateRect(Application.MainForm.ClientHandle, nil, True);
end;

C++:

SendMessage(Application->MainForm->ClientHandle, WM_SETREDRAW, FALSE, 0);
try
{
  Child = new TChildForm(this);
  Child->Left = ...;
  Child->Top = ...;
  Child->Show();
}
__finally
{
  SendMessage(Application->MainForm->ClientHandle, WM_SETREDRAW, TRUE, 0);
  InvalidateRect(Application->MainForm->ClientHandle, NULL, TRUE);
}
Goodall answered 18/8, 2010 at 1:0 Comment(2)
Thanks. I had to use RedrawWindow instead of InvalidateRect to get the MDI children to redraw properly, as described at msdn.microsoft.com/en-us/library/dd145219%28VS.85%29.aspx under "Remarks."Suber
I use InvalidateRect() and it works fine for me. The Remarks refer to a ListBox, not an MDI window.Goodall
N
1

I observe no flickering at all, but that might be because my computer is too fast or it might be an improvement in Windows 7 to reduce flickering.

I set the MDI child window position at its FormShow:

procedure TForm2.FormShow(Sender: TObject);
begin
  Top := 200;
  Left := 400;
end;
Nonconformist answered 17/8, 2010 at 21:37 Comment(1)
Thanks. I was trying to do it from the constructor and hadn't realized that OldCreateOrder was set to true. Once I fixed OldCreateOrder, using the constructor and FormShow both work.Suber

© 2022 - 2024 — McMap. All rights reserved.