Delphi中的OnShow主窗体/模式窗体

8
我有一个项目,其中包含一个主窗体和其他一些窗体。当应用程序加载时,它需要执行一些任务,并在主窗体上方显示模态窗体中的结果。 我的问题是,如果我将调用执行任务/创建并显示模态窗体的函数放在主窗体的onshow事件中,那么模态窗体会出现,但主窗体直到关闭模态窗体才会出现,这正是我所期望的。为了解决这个问题,我在主窗体中添加了一个计时器,并在主窗体的onshow事件中启动它,计时器调用执行任务/创建并显示模态窗体的函数。所以现在主窗体会在模态窗体之前出现。
然而,我认为这不是最好的解决方案,想知道是否有更好的解决方案。
我正在使用Delphi 7。
Colin

1
使用PostMessage。http://stackoverflow.com/questions/7094873/visibility-of-form-in-delphi - SimaWB
抱歉离题了,但为什么这个问题在主问题列表中显示为“模糊”? - kobik
据我所知,当问题有你忽略的标签或者负分超过一定限制时,它们会显示为暗淡。另外,关于SO工作方式的问题最好在元站点上提问(请参见主导航中的链接)。 - Marjan Venema
3个回答

10

常见的一种方法是在表单的OnShow事件中向自己发布一条消息,代码如下:

const
  WM_SHOWMYOTHERFORM = WM_USER + 0;

type
  TMyMainForm = class(TForm)
    procedure FormShow(Sender: TObject);
  protected
    procedure WMShowMyOtherForm(var Message: TMessage); message WM_SHOWMYOTHERFORM;
  end;

...


procedure TMyMainForm.FormShow(Sender: TObject);
begin
  PostMessage(Handle, WM_SHOWMYOTHERFORM, 0, 0);
end;

procedure TMyMainForm.WMShowMyOtherForm(var Message: TMessage);
begin
  inherited;
  with TMyOtherForm.Create(nil) do begin
    try
      ShowModal;
    finally
      Free;
    end;
  end;
end;

2
虽然这是解决方案的正确思路,但所示实现并不太好。 :) 使用自定义消息,并为该特定消息实现处理程序,而不是替换整个 WndProc。只需在表单类型声明之前声明自定义消息,并添加 procedure UMShowMyOtherForm(var Message: TMessage); message UM_SHOWMYOTHERFORM;。然后,唯一中断 WndProc 正常流程的是您的自定义消息。 - Ken White
1
@MarcusAdams OnShow 事件处理程序在调用 ShowWindow 之前被调用。因此,也许更好地命名为 OnJustBeforeShow。对于第一次显示主窗体,这是在启动主线程消息泵(Application.Run)之前的最后一个操作。向队列发布消息可以确保在处理排队的消息之前进行对 ShowWindow 的调用。然而,研究这个问题让我找到了更好的解决方案...... - David Heffernan
我没有说 OnShow;我说的是 constructor。:) 表单的构造函数只会被调用一次。 :) - Ken White
@Ken,好的,现在看到了。我想你最好希望在主窗体显示之前没有任何东西会推动队列。不想要任何流氓的ProcessMessages。我仍然认为这个答案很差,另一个答案才是正确的方式。冒险猜测队列何时被推动似乎很危险。 - David Heffernan
1
我从不使用ProcessMessages绝对不会。因此也不可能存在这样的情况。我也不使用使用ProcessMessages的第三方组件。而且我不使用没有源代码的第三方组件,所以它们也无法悄悄地通过。 :) - Ken White
显示剩余11条评论

2
为什么不像这样使用MainForm OnActivate事件呢?涉及IT技术相关内容。
procedure TMyMainForm.FormActivate(Sender: TObject);
begin
  //Only execute this event once ...
  OnActivate := nil;

  //and then using the code David Heffernan offered ...
  with TMyOtherForm.Create(nil) do begin
    try
      ShowModal;
    finally
      Free;
    end;
end;

将事件设置为nil将确保此代码仅在启动时运行一次。

0

OnShow事件在调用Windows API函数ShowWindow之前立即触发。正是这个对ShowWindow的调用实际上导致窗口出现在屏幕上。

因此,你最好需要在调用ShowWindow之后立即运行某些东西。事实证明,驱动所有这些的VCL代码位于CM_SHOWINGCHANGEDTCustomForm消息处理程序中。该消息处理程序触发OnShow事件,然后调用ShowWindow。因此,一个很好的解决方案是在CM_SHOWINGCHANGED处理程序运行后立即显示模态窗体。像这样:

type
  TMyMainForm = class(TForm)
  private
    FMyOtherFormHasBeenShown: Boolean;
  protected
    procedure CMShowingChanged(var Message: TMessage); message CM_SHOWINGCHANGED;
  end;

.....

procedure TMyMainForm.CMShowingChanged(var Message: TMessage);
begin
  inherited;
  if Showing and not FMyOtherFormHasBeenShown then begin
    FMyOtherFormHasBeenShown := True;
    with TMyOtherForm.Create(nil) do begin
      try
        ShowModal;
      finally
        Free;
      end;
    end;
  end;
end;

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