应用程序加载时确保主窗体已最大化并完全重绘以显示模态窗体的正确方法。

12

在应用程序首次加载时,建议采取什么方式来确保主窗体完全最大化并重新绘制所有控件后再显示模态窗体?

我需要在应用程序启动时显示模态对话框(不是登录屏幕),但如果我将窗体设置为 wsMaximized,则屏幕最大化时,控件将没有机会重新绘制,留下一个丑陋的混乱。

目前,我使用以下方式显示模态屏幕:

procedure TForm1.FormActivate(Sender: TObject);
var
  frmOrderLookup:TfrmOrderLookup;
begin
  onactivate := nil;
  frmOrderLookup:=TfrmOrderLookup.Create(nil);
  try
    frmOrderLookup.showmodal;
  finally
    frmOrderLookup.Free;
  end;
end;
1个回答

14

我通常会将自定义消息发送回我的表单。这样,直到表单的其他消息已经处理完毕之前,它才会被处理。当此消息被处理时,您的表单应该已经完成了重绘。

type
  TMyForm = class(TForm)
    procedure FormCreate(Sender: TObject);
  private
    procedure HandleLookupMessage(var Message: TMessage); message WM_USER + 1;
  end;

procedure TMyForm.HandleLookupMessage(var Message: TMessage);
var
  frmOrderLookup: TfrmOrderLookup;
begin
  frmOrderLookup := TfrmOrderLookup.Create(Application);
  try
    frmOrderLookup.ShowModal;
  finally
    frmOrderLookup.Release;
  end;
end;

procedure TMyForm.FormCreate(Sender: TObject);
begin
  // Maximise form here if needed
  PostMessage(Handle, WM_USER + 1, 0, 0);
end;

如果你担心消息会以某种方式再次传递到你的应用程序中,你可以始终添加一个私有的布尔变量来指示它已经被处理过一次。


1
如果您在 OnShow 中发布消息,它将稍后处理;这消除了任何过早发送的可能性。 (难道不应该是 FormCreate 吗? OnCreate 是属性本身的名称。) - Ken White
@Ken:感谢您的纠正。至于使用OnShow,我认为在Application.Run开始泵送消息队列之前,窗体将被创建、显示和激活,所以这并不重要。其他窗体和数据模块也将首先被创建(并触发它们的OnCreate事件)。在实践中,当从OnCreate中使用时,我还没有遇到过这种用法失败的情况。 - afrazier
感谢您的帮助 - 同时也要给@KenWhite加上+1,因为他推荐了OnShow。 - Mark Robinson
@afrazier:除非你的表单上有第三方组件在创建时调用了Application.ProcessMessages或类似的操作。:-)在OnActivate中执行此操作的问题是,你必须记住禁用OnActivate,因为它可能会被触发多次。在OnShow中执行此操作解决了这两个潜在的问题。 - Ken White
@Ken:OnShow 可能会再次触发,因此也需要取消挂钩。主窗体被隐藏然后重新显示是不常见的,但并非不可能。而且,什么样的可怕的第三方组件会在创建期间调用 Application.ProcessMessages?哎呀!请告诉我,这样我就可以远离它了。 - afrazier
它们就在那里。相信我,我以前曾经在不再使用的产品中追踪过它们的错误。我更喜欢尽可能晚地在创建过程中发布消息,但你可以随意选择。如果我看到你的问题可以通过这样做来解决,我会回答说“我早就告诉你了!我早就告诉你了!”并指向这里。 <g> - Ken White

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