首页 > 解决方案 > Delphi 主窗体在禁用/启用后落后于其他应用程序

问题描述

我有一些 vcl mdi 应用程序,我需要在其中做一些工作,并在它上面显示另一种非模态形式的进度。因为这个进度表是从某个线程更新的,并且上面有一些按钮(取消操作),所以我使用 application.ProcessMessages 更新进度。在此过程中,我需要禁用所有主要表单控件。我这样做:

MainForm.enabled := false;
... do some work here, update progress ...
MainForm.enabled := true;

不过,在此之后,我的主要表单进入了其他不酷的 Windows 应用程序。如果我删除启用/禁用这两条线 - 它应该保持在顶部。

任何想法如何解决它?

标签: formsdelphivcl

解决方案


一个简单的BringTofront作品。它可以在设置enabled为之前或之后true

MainForm.enabled := false;
// ... do some work here, update progress ...
MainForm.enabled := true;
MainForm.BringTofront;

或者

MainForm.enabled := false;
// ... do some work here, update progress ...
MainForm.BringTofront;
MainForm.enabled := true;

编辑:正如下面评论的那样,使用上面的代码,主窗体将在它成为焦点之前落后于其他窗体。这发生在 Delphi 7 中,但在 Delphi 2009 中似乎没有。

当当前活动窗体关闭或隐藏时,Delphi 会尝试切换到主窗体。但是,如果主窗体被禁用,Delphi 将无法激活它并将其移到后面。解决方案相当简单,只需在隐藏或释放其他表单之前设置Enabled为正确即可。true没有必要打电话BringTofront

MainForm.enabled := false;
ProgressForm.Show;  // Or Application.CreateForm(...)
// ... do some work here, update progress ...
MainForm.enabled := true;
ProgressForm.Hide;  // Or ProgressForm.Free;

编辑:这是导致此行为的 Delphi 代码:

procedure TCustomForm.CMShowingChanged(var Message: TMessage);
  ....
begin
  ....
      NewActiveWindow := 0;
      if (GetActiveWindow = Handle) and not IsIconic(Handle) then
        NewActiveWindow := FindTopMostWindow(Handle);
      if NewActiveWindow <> 0 then
      begin
        SetWindowPos(Handle, 0, 0, 0, 0, 0, SWP_HIDEWINDOW or
          SWP_NOSIZE or SWP_NOMOVE or SWP_NOZORDER or SWP_NOACTIVATE);
        SetActiveWindow(NewActiveWindow);
      end else
        ShowWindow(Handle, SW_HIDE);
  ....
end;

另一个解决方法是处理CM_SHOWINGCHANGED第二种形式的消息:

procedure CMSHOWINGCHANGED(var Message: TMessage); message CM_SHOWINGCHANGED;

procedure TProgressForm.CMSHOWINGCHANGED(var Message: TMessage);
begin
  if not visible then
     Application.MainForm.Enabled := True;
  inherited;
end;

推荐阅读