我有一个使用Chrome浏览器等标签的应用程序。现在我希望能够打开更多表格而不仅限于一种表格。这些表格应该是相同的,但如果我关闭主表格,所有表格都将被关闭。如何使所有表格都相同,所以无论我关闭哪种表格,只关闭该表格而不是在所有表格关闭之前退出申请表?有什么想法吗?
亲切的问候 Roy M Klever
答案 0 :(得分:16)
要做到这一点并不难,尽管它会根据你想要的完整程度而迅速变得复杂。让多个模态对话框独立工作需要付出很多努力。
首先,您需要完全避免使用Application.MainForm。始终使用Form := TMyForm.Create(Application)
代替Application.CreateForm(TMyForm, Form)
。后者设置了MainForm,你永远不希望这种情况发生。
为了让事情正常关闭,您需要在表单的OnClose
事件处理程序中执行以下操作:
if Screen.FormCount = 1 then
Application.Terminate;
CloseAction := caFree;
Application.Run
依赖于分配的MainForm,因此在您的DPR中用此循环替换该行:
repeat
try
Application.HandleMessage;
except
Application.HandleException(Application);
end;
until Application.Terminated;
有几种方法可以处理任务栏条目。
单个任务栏条目:设置Application.MainFormOnTaskbar := False;
并使用隐藏的TApplication句柄。单击任务栏条目将使所有窗口都显示在前面。您需要覆盖Application.OnMessage
或添加TApplicationEvents
组件,并使用Msg.Handle = Application.Handle`查看WM_CLOSE
。在这种情况下,用户右键单击任务栏并选择关闭,因此您应该关闭所有窗口。
多个任务栏条目:设置Application.MainFormOntaskbar := True
。覆盖表单的CreateParams
方法并设置Params.WndParent := 0;
。每个任务栏条目都将控制该表单。
可能还有其他一些问题,但这是基础知识。
正如我所说,让ShowModal
和TOpenDialog/TSaveDialog
独立工作,所以它只影响其父形式,因此可以同时打开多个对话框,是大量的工作,我不能真的推荐它。如果你是受虐狂,这里是一般步骤:
将TCustomForm.ShowModal
替换为自定义版本。除此之外,该例程会禁用应用程序中的所有其他窗口,因此您需要将DisableTaskWindows/EnableTaskWindows
调用替换为EnableWindow(Owner.Handle, False/True)
才能禁用父窗体。此时,您可以打开多个对话框,但它们只能以后进先出顺序关闭,因为调用最终是递归的。如果没关系,请停在这里。
有两种方法可以解决这个问题:
不要进行ShowModal
阻止,而是拥有StartModal
和EndModal
例程,这些例程具有ShowModal代码的第一位和最后一位,并在调用OnShowModalDone
事件时调用对话框已关闭。这是一种使用起来很痛苦,但是相对容易编码并且易于稳定。
使用Windows fiber routines交换堆栈并启动新的消息循环。这种方法很容易使用,因为ShowModal
是阻塞的,所以你可以像平常一样调用它。这是我们在Beyond Compare中使用的方法。 不要这样做。编写起来很复杂,因为与第三方代码不兼容(Windows全局消息挂钩,TWebBrowser, 会导致非平凡应用程序的稳定性问题由浏览对话框加载的shell扩展中的.NET等,如果它是跨平台项目,则Unix ucontext函数也不安全。
常见对话框(TOpenDialog,TColorDialog等)也有类似的限制。要使它们仅禁用父表单,您需要覆盖TCommonDialog.TaskModalDialog
并替换那里的DisableTaskWindows/EnableTaskWindows
调用。它们不能像上面的常规Delphi对话那样异步,因为它们阻止了Windows提供的功能(GetOpenFileName,ChooseColor等)。允许那些以任何顺序关闭的唯一方法是让每个对话框在专用线程中运行。只要您小心访问VCL对象,Windows就可以处理大部分同步,但它基本上涉及重写Dialogs.pas
的大部分内容。
答案 1 :(得分:2)
如果你真的想那,
1)使用一个小的,可能隐藏的MainForm,并在启动时启动第一个子窗体。
2)在同一进程中启动单独的应用程序而不是Windows。这是Office后来使用的版本。
答案 2 :(得分:2)
这是一个类似的StackOverflow问题: Multiple app windows activation not working correctly
在我的情况下,我不会像Craig描述的那样避免使用MainForm。相反,我隐藏了主窗口,我所有的真实窗口都是其他非模态窗体。我对我的应用程序如何工作感到满意,但Craig的方法可能更简单。
请参阅我对上述问题的回答,查看我的方法的代码示例以及一些具有良好背景信息的链接。
答案 3 :(得分:1)
在Delphi应用程序中创建的第一个表单被视为主表单,当该表单关闭时应用程序终止。显而易见的解决方案是让第一个表单不是由用户关闭的表单,而是用户不可见的表单,只有在所有其他表单都已关闭时才会关闭。
我没试过,但它应该有用。
答案 4 :(得分:0)
现在为时已晚,无法回答,但我遇到了同样的问题。我选择的解决方案是提取Application.ExeName
并将其传递给createProcess
甚至shellExecute
等函数。所以,现在我在OS级别拥有独立的应用程序。我还需要不同实例的不同任务栏按钮。