当主窗体最小化时隐藏fsStayOnTop窗体/防止自动恢复

3
我有一个类似于这里提问的问题的主表单和状态表单。然而,我的状态窗口的FormStyle是fsStayOnTop,这会在我尝试最小化主窗体时导致一些奇怪的行为。
当我最小化主窗体时,两个窗体都会按预期隐藏,但当状态窗体完成它的任务并被最小化时,主窗体会自动恢复其自身,并且它的最小化按钮不再起作用(但最大化/还原/关闭仍然有效)。唯一的方法是重新启动应用程序以使最小化功能再次起作用。如果我将FormStyle设置为其他任何值,则一切正常,但我的应用程序要求状态窗体在可见时始终保持在顶部。
为什么主窗体会自动恢复呢?有没有办法解决这个问题?
procedure ButtonClick(sender:TObject);
begin
  //Gather some data

  ShowStatusWindow; // sets status window to visible, does its work, 
                    // then sets invisible. (Usually visible for about 10 seconds)

  //Gather more data

  Windows.SendMessage(self.Handle, WM_SETREDRAW, 0, 0); //Freeze the main form for 
                                                        //flickerless drawing
  // Handle everything that would cause a redraw
  Windows.SendMessage(self.Handle, WM_SETREDRAW, 1, 0);  // thaw form
  RedrawWindow(self.Handle, 0, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN);
end;

最合理的解释是您有一些代码导致主窗体在工作完成时恢复。 - Sertac Akyuz
@SertacAkyuz 如果我唯一改变的是窗体样式,比如fsNormal,那么它就可以正常工作,窗口不会恢复。只有当我将窗体样式设置为fsStayOnTop时,才会出现恢复和最小化停止工作的情况。没有其他代码不同。 - Evan Zimmerman
2
我们如何复制这种行为? - Sertac Akyuz
1
我不明白为什么你希望我们从模糊的描述中尝试重新创建程序。在过去,我的客户通常会通过传真向我发送数据,然后我会将其输入或通过电话读出来,然后才能帮助他们。现在我们可以通过电子邮件发送文件。你只需将一个SSCCE粘贴到问题中,我们就可以在几分钟内为你提供答案。不要让这变得困难。如果你给我们提供SSCCE,那么这真的很容易。 - David Heffernan
抱歉,我正在尝试创建一个小应用程序来复制问题,因为原始源代码处理此问题的行数达到了数千行。由于某种原因,在这个小应用程序中(只有两个表单和一个按钮点击事件来显示fsStayOnTop表单足够长的时间以在完成之前将其最小化),问题不会发生。如果有帮助的话,我可以概述当表单被显示时会发生什么。 - Evan Zimmerman
2
有助于解决问题的是SSCCE。 - David Heffernan
1个回答

5
我能想到的唯一解释是,您应用程序的 MainFormOnTaskbar 属性设置为 false。
如果是这种情况,当您的应用程序最小化时,主窗体实际上并没有最小化,而是根据 VCL 的最小化机制隐藏了起来。 当您发送一个 'wParam' 设置为 True 的 WM_SETREDRAW 消息时,您正在强制显示被隐藏(未最小化)的主窗体窗口。
此时,根据 VCL,应用程序仍处于最小化状态,因为它从未被还原过。当您单击主窗体的最小化按钮时,VCL 调用 TApplication.Minimize 并查看应用程序窗口是否已经最小化,因此不会执行进一步操作,因此主窗体不会被最小化。
以下是可重现该问题的简单示例。在项目源中将 MainFormOnTaskbar 设置为 false。运行应用程序,然后单击按钮:
procedure TForm1.Button2Click(Sender: TObject);
begin
  Application.Minimize;
  SendMessage(Handle, WM_SETREDRAW, 1, 0);
  // ShowWindow(Handle, SW_SHOWNORMAL); // this will also do the same
end;

你在这之后就无法最小化表单。
要解决这个问题,你可以在禁用绘图之前检查主表单是否可见。
  if IsWindowVisible(Handle) then begin
    Windows.SendMessage(self.Handle, WM_SETREDRAW, 0, 0);
    ...

感谢您的帮助。您是正确的。移除窗口冻结/解冻确实使得表单在最小化时不会恢复。但是,当状态表单的样式设置为fsNormal时,您有任何想法为什么它仍然保持最小化吗?在这种情况下,当表单被告知重新绘制时是否会发生特殊的事情(或不会发生)?这可能与StayOnTop和OnTaskbar有关吗?谢谢。 - Evan Zimmerman
@Evan - 不客气。实际上,我无法直接想到任何东西。既然你观察到了差异,显然存在关联。我记得在D2007中,“Normalize/RestoreTopMosts”是有问题的,但我不确定它是否与此有关。我认为我们真的需要一个测试用例来看看发生了什么。 - Sertac Akyuz

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