如何在Delphi中隐藏MDI子窗体?

4

如何在Delphi中隐藏MDIChild窗口?

我在我的MDI子窗体的FormClose()事件中使用了以下代码,但它似乎不起作用:

procedure TfrmInstrument.FormClose(Sender: TObject; var Action: TCloseAction);
begin
  Action := caNone;
  ShowWindow(Handle, SW_HIDE);
  frmMainForm.MDIChildClosed(Handle);
end;

我的子窗口被最小化了,而不是隐藏了。


@AndreasRejbrand 我不想销毁并重新创建一个类似的窗口,因为每个子窗口都会加载一些库,打开串口和其他一些初始化工作,这需要几秒钟的时间。所以,在启动时创建所有子窗体,使用ShowWindow隐藏它们(具有讽刺意味的是,这里可以正常工作),当用户选择一个窗体时再显示它们,并在用户关闭它们时再次隐藏它们。 - iMan Biglari
2
@iManBiglari:如果将所有组件及其相关代码移动到每个 MDI 子窗口的数据模块中,并将 MDI 子窗口视为一个简单的视图(可以随意打开和关闭),那么您就不需要与 MDI 窗口子系统抗争了。我敢说,这样的改变会改善程序设计。 - mghie
@mghie 嗯,使用框架比数据模块更合适。 - David Heffernan
@iManBiglari:我不明白这有什么关系。但是,如果你决定在单个单元中实现它,那么创建一个包含所有内容的单元私有工作类,而不是使用数据模块。如果使用线程实现,可以获得额外的奖励积分,这样用户就不必等待长时间的初始化程序完成,而且它们可能会并行运行。 - mghie
1
@mghie 我不明白为什么你需要数据模块来实现这种分离。我想它可以帮你省去实例化组件的样板代码,但我从未觉得那特别有吸引力。 - David Heffernan
显示剩余6条评论
2个回答

10

TCustomForm中有一个受保护的过程,定义如下:

procedure TCustomForm.VisibleChanging;
begin
  if (FormStyle = fsMDIChild) and Visible and (Parent = nil) then
    raise EInvalidOperation.Create(SMDIChildNotVisible);
end;

在你的 MDI 子窗口中如下覆盖它:

procedure TMDIChildForm.VisibleChanging;
begin
  // :-P
end;

这里有一个简单的例子

在阅读了Jeroen的评论后,我尝试了另一种解决方案,它也能正常工作,但会有轻微的闪烁:

procedure TMDIChildForm.VisibleChanging;
begin
  if Visible then
    FormStyle := fsNormal
  else
    FormStyle := fsMDIChild;
end;

也许这适用于所有的Windows版本。

PS:我在Windows 2k3SP2 x86和Windows 7 Ultimate x86上没有发现第一个解决方案存在任何问题。


2
Windows 中的 MDI 支持存在一些错误,这些错误(至少在我在 90 年代研究时)被列入 Microsoft 的“不会修复”列表。这是很多看起来像 MDI 的 Microsoft 应用实际上没有使用 Windows MDI 代码的原因之一。TCustomForm.VisibleChanging 阻止这些错误出现。因此,您的建议可能导致您的应用在某些 Windows 版本上失败。 - Jeroen Wiert Pluimers
1
+1;那个答案(设置FormStyle)确实可以绕过这些错误。我相信这些错误从Windows 3.0一直持续到Windows 2000左右。之后,我只使用SDI和Outlook样式的应用程序。 - Jeroen Wiert Pluimers
我会在所有目标操作系统版本上广泛测试解决方案1。如果它有效,我会说继续使用它。我的猜测是TCustomForm.VisibleChanging背后的原因已经失落在时间的深处。也许你可以在Emba论坛上询问,看看老一辈的Emba开发人员是否能记得这个理由。 - David Heffernan
@DavidHeffernan 到目前为止,它可以在XP SP3、2k3 SP2和7 SP1上运行。这个周末我会在我的衣柜里找我的2k安装光盘,我猜任何更早的操作系统都是浪费时间。 - iMan Biglari
2
我经常在工业领域看到DOS、Windows 95和Windows NT 4的解决方案。它们大多是独立系统,用于与机器进行接口交互。 - Jeroen Wiert Pluimers
显示剩余2条评论

0

你无法隐藏一个 MDI 子窗口。这是 Win32 的限制。


但是为什么MDI子窗口抵制ShowWindow() API调用呢? - iMan Biglari
因为这样的窗口并不是设计成可以隐藏的。 - Andreas Rejbrand
我相信Andreas是正确的,但我不确定为什么会做出这个设计决定。毫无疑问,您已经尝试调用“Hide”,然后在VCL引发“无法隐藏MDI子窗口”错误时放弃了。但这就是VCL告诉您不支持此操作的方式。 - David Heffernan
@DavidHeffernan 我翻看了一下 Vcl.Forms.pas 文件,找到了这个过程:`procedure TCustomForm.VisibleChanging; begin if (FormStyle = fsMDIChild) and Visible and (Parent = nil) then raise EInvalidOperation.Create(SMDIChildNotVisible); end;`我在我的 MDI 子窗体中重写了它,第一次隐藏时我的窗体被隐藏了。但第二次它又自动最小化了。所以我想我走在了正确的轨道上。 - iMan Biglari
当我尝试您的解决方案时,平铺和级联对我不起作用。 - David Heffernan
显示剩余7条评论

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