【问题标题】:Delphi main form goes behind other applications after disable/enableDelphi 主窗体在禁用/启用后落后于其他应用程序
【发布时间】:2019-01-05 23:43:42
【问题描述】:

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

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

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

有什么解决办法吗?

【问题讨论】:

  • 使用模态表单
  • 出于某种原因,我不喜欢使用模态形式。还有其他想法吗?
  • 尝试确定原因。然后尝试了解 ShowModal 的作用。然后尝试识别该原因如何适用于两者,即 ShowModal 和禁用主窗体。然后尝试找出两者的区别(提示:VCL 做得很好)。
  • 如果您要禁用主表单,那么您也可以使用模态表单表单进度。这样做会正确禁用主窗体。
  • 用 ShowModal 显示的模态表单会等待该函数返回到主进程。我的进度表是从许多不同的地方调用的,除了显示进度之外什么都不做。所有工作都在其他地方完成。这就是为什么我不使用模态形式。

标签: forms delphi vcl


【解决方案1】:

一个简单的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;

【讨论】:

  • 它可以工作,但是......主窗体首先进入其他窗口,然后返回,看起来不太好。效果与 Windows.SetActiveWindow(handle);
【解决方案2】:

好的,看来我找到了解决方案。进度表的 PopupMode 设置为 pmAuto。在这种情况下,主窗体保持在顶部。

它是这样工作的:

procedure TMainForm.DoSomenthing;
begin
  enabled := false;
  try
    // open progress form
    Include(ProgressFrm.FFormState, fsModal);
    ProgressFrm.Show;

    .... do something, update progress ....

    // close progress form
    ProgressFrm.Hide;
    Exclude(ProgressFrm.FFormState, fsModal);
  finally
    enabled := true;
    BringToFront;
  end;
end;

【讨论】:

  • 只需在enabled := true; 之后移动ProgressFrm.Hide; 即可。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2014-08-17
  • 2010-10-15
  • 1970-01-01
  • 1970-01-01
  • 2014-10-29
  • 2012-10-23
  • 1970-01-01
相关资源
最近更新 更多