Delphi - 创建隐藏的 MDI 子窗体

6

我的应用程序有许多许多mdi表单,它们在用户成功登录后创建。我如何最好地隐藏这个创建过程?它看起来很愚蠢,而且当新表单被创建并绘制mdi表单时,需要更长的时间。

到目前为止,我已经使用了LockWindowUpdate,它不能隐藏所有内容,但我想使用一个显示创建进度的启动画面,但是我不能使用LockWindowUpdate。

最好的问候 Janne


1
不要在启动时创建它们。需要时再创建它们。 - David Heffernan
如何避免在菜单窗口列表中绘制隐藏子窗口的信息? - Antonio Linares Cañas
3个回答

9
要创建不可见的 MDI 子窗体,您需要将它们的 Visible 属性设置为 False。此外,您还需要禁用 VCL 在创建过程中强制显示它们的行为。这是通过 TCustomFormFormStyle 属性设置器完成的,该属性设置器会为 MDI 子窗体设置 VisibleTrue

如果您在对象检查器中设置了 FormStyle,则属性设置器将在表单创建期间被调用,表单将不会立即显示,而是在构造完成后才显示。这使您可以通过重写 AfterConstruction() 方法来重置显示表单的请求,方法如下:

procedure TMDIChild.AfterConstruction;
begin
  Exclude(FFormState, fsVisible);
  inherited;
end;

这将创建一个隐形的 MDI 子窗体。
为测试此功能,您可以在 IDE 中创建一个新的 MDI 应用程序,覆盖子窗体类中所示的方法,并模拟长时间初始化:
procedure TMainForm.FileNew1Execute(Sender: TObject);
var
  i: integer;
begin
  for i := 1 to 10 do begin
    CreateMDIChild('NONAME' + IntToStr(MDIChildCount + 1));
    Update;
    Sleep(500);
  end;
  for i := 0 to MDIChildCount - 1 do
    MDIChildren[i].Visible := True;
end;

没有重写 AfterConstruction() 方法,它会每半秒钟创建和显示一个 MDI 子窗体。使用重写方法后,它将在 5 秒钟的繁忙期之后显示所有子窗体,这将为您提供展示启动画面的机会。
重要提示:
使用 LockWindowUpdate() 来减少闪烁或抑制任何屏幕输出都是错误的。绝对不要这样做,阅读关于该主题的 Raymond Chen articles 系列文章以了解为什么。不要这样做

+1,这是一种非常整洁的、仅适用于Delphi的方法。我通常不得不使用Win API(ShowWindow)来实现这一点。 - Gerry Coll
太好了!这正是我正在寻找的,并且有了Raymond Chen的提示,我可以禁用visible := true循环的重绘。 非常感谢您 :) - HeartTune

0

我曾经遇到过MDI子窗口闪烁的类似问题。我使用了重写AfterConstructionWM_SETREDRAW消息的组合,参考了这个提示: 在Delphi中控制fsMDIChild窗口的放置

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;

一切都运行良好。


0

试一下这段代码,它对我很有效

 try
  SendMessage(Application.MainForm.ClientHandle,WM_SETREDRAW,0,0);
  FormChild:=TBaseChildForm.Create(application);
  FormChild.Caption:='Form '+IntToStr(n);
  FormChild.Show;
 finally
  SendMessage(Application.MainForm.ClientHandle,WM_SETREDRAW,1,0);
  RedrawWindow(Application.MainForm.ClientHandle, nil, 0, RDW_FRAME or RDW_INVALIDATE or   RDW_ALLCHILDREN or RDW_NOINTERNALPAINT);
 end;

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接