Управление размещением окон fsMDIChild в Delphi

Как управлять размещением дочернего окна MDI (FormStyle := fsMDIChild) в Delphi или C++Builder? Я знаю, что могу установить Left, Top, Position и т. д., но, в частности, для дочернего MDI они не вступят в силу до тех пор, пока окно уже не будет создано и показано в его местоположении по умолчанию. В результате создание и позиционирование нескольких окон одновременно приводит к незначительному мерцанию, поскольку окна создаются в положениях по умолчанию, а затем немедленно перемещаются и изменяются в размерах.

Изучая исходный код VCL, единственное решение, которое я смог найти, — это переопределить метод CreateParams TCustomForm и изменить поля X, Y, Width и Height параметра Params, но это похоже на хак. Есть ли более чистый способ сделать это?


person Josh Kelley    schedule 17.08.2010    source источник


Ответы (2)


Я вообще не наблюдаю мерцания, но это может быть потому, что мой компьютер слишком быстрый, или это может быть улучшением Windows 7 для уменьшения мерцания.

Я установил положение дочернего окна MDI в его FormShow:

procedure TForm2.FormShow(Sender: TObject);
begin
  Top := 200;
  Left := 400;
end;
person Andreas Rejbrand    schedule 17.08.2010
comment
Спасибо. Я пытался сделать это из конструктора и не понял, что OldCreateOrder имеет значение true. Как только я исправил OldCreateOrder, использование конструктора и FormShow работает. - person Josh Kelley; 18.08.2010

Вы можете отправить WM_SETREDRAW сообщения в ClientHandle MainForm, одно с параметром wParam, установленным на False, а затем позже с параметром wParam, установленным на True, чтобы избежать мерцания при настройке дочернего окна MDI, например:

Дельфи:

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);
}
person Remy Lebeau    schedule 18.08.2010
comment
Спасибо. Мне пришлось использовать RedrawWindow вместо InvalidateRect, чтобы заставить дочерние элементы MDI правильно перерисовываться, как описано в msdn.microsoft.com/en-us/library/dd145219%28VS.85%29.aspx в разделе "Примечания". - person Josh Kelley; 18.08.2010
comment
Я использую InvalidateRect(), и он отлично работает для меня. Примечания относятся к ListBox, а не к окну MDI. - person Remy Lebeau; 20.08.2010