Delphi,如何制作独立的窗口 [英] Delphi, how to make independent windows
问题描述
我有一个使用 Chrome 浏览器等标签的应用程序.现在我希望能够打开更多的表单,而不是仅限于一个表单.这些表单的行为应该相同,但如果我关闭主表单,所有表单都将关闭.我怎样才能使所有表单都相等,所以无论我关闭哪个表单,它只会关闭该表单而不是在所有表单关闭之前退出应用程序?有什么想法吗?
I have an application that uses tabs like the Chrome browser. Now I want to be able to open more forms and not be limited to only one form. These forms should act the same but if I close main form all forms are closed. How can I make all forms be equal, so no matter which form I close it only closes that form and not exit application before all forms are closed? Any ideas?
亲切的问候罗伊·M·克莱弗
Kind Regards Roy M Klever
推荐答案
这并不难,尽管它会很快变得复杂,具体取决于您希望它有多完整.让多个模态对话框独立工作是一项艰巨的工作.
It's not too hard to do this, though it starts getting complicated quickly depending on how complete you want it to be. Getting multiple modal dialogs to work independently is a ton of effort.
首先,您需要完全避免 Application.MainForm.始终使用 Form := TMyForm.Create(Application)
而不是 Application.CreateForm(TMyForm, Form)
.后者设置 MainForm,您永远不希望发生这种情况.
To start, you need to avoid Application.MainForm entirely. Always use Form := TMyForm.Create(Application)
instead of Application.CreateForm(TMyForm, Form)
. The later sets MainForm and you never want that to happen.
要使事情正常关闭,您需要在表单的 OnClose
事件处理程序中执行类似的操作:
To make things shut down properly you'll need to do something like this in your form's OnClose
event handler:
if Screen.FormCount = 1 then
Application.Terminate;
CloseAction := caFree;
Application.Run
依赖于分配的 MainForm,因此在您的 DPR 中用此循环替换该行:
Application.Run
relies on MainForm being assigned, so in your DPR replace that line with this loop:
repeat
try
Application.HandleMessage;
except
Application.HandleException(Application);
end;
until Application.Terminated;
有几种方法可以处理任务栏条目.
There are a couple of ways to handle the taskbar entry.
单个任务栏条目:设置
Application.MainFormOnTaskbar := False;
将使用隐藏的 TApplication 句柄.单击任务栏条目会将所有窗口置于前面.您需要覆盖Application.OnMessage
或添加TApplicationEvents
组件,并使用 Msg.Handle = Application.Handle 观察WM_CLOSE
.在这种情况下,用户已右键单击任务栏并选择了关闭,因此您应该关闭所有窗口.
Single taskbar entry: Set
Application.MainFormOnTaskbar := False;
and the hidden TApplication handle will be used. Clicking on the taskbar entry will bring all of the windows to the front. You'll need to overrideApplication.OnMessage
or add aTApplicationEvents
component, and watch forWM_CLOSE
with the Msg.Handle = Application.Handle`. In that case the user has right-clicked on the taskbar and selected Close, so you should close all the windows.
多个任务栏条目:设置 Application.MainFormOntaskbar := True
.覆盖表单的 CreateParams
方法并设置 Params.WndParent := 0;
.每个任务栏条目都将控制该表单.
Multiple taskbar entries: Set Application.MainFormOntaskbar := True
. Override your form's CreateParams
method and set Params.WndParent := 0;
. Each taskbar entry will control that form.
可能还有一些其他的陷阱,但这是基础知识.
There are probably a few other gotchas, but that's the basics.
正如我所说,使 ShowModal
和 TOpenDialog/TSaveDialog
独立工作,所以它只影响其父窗体,因此可以一次打开多个对话框,是一吨工作,我真的不能推荐它.如果您是受虐狂,以下是一般步骤:
As I said, making ShowModal
and TOpenDialog/TSaveDialog
working independently, so it only affects its parent form and so multiple dialogs can be open at once, is a ton of work, and I can't really recommend it. If you're a masochist, here's the general steps:
将
TCustomForm.ShowModal
替换为自定义版本.除此之外,该例程会禁用应用程序中的所有其他窗口,因此您需要将DisableTaskWindows/EnableTaskWindows
调用替换为EnableWindow(Owner.Handle, False/True)
只是禁用父窗体.此时您可以打开多个对话框,但它们只能以后进先出的顺序关闭,因为调用最终是递归的.如果没问题,就到此为止.
Replace
TCustomForm.ShowModal
with a custom version. Among other things, that routine disables all the other windows in the application, so you need to replace theDisableTaskWindows/EnableTaskWindows
calls withEnableWindow(Owner.Handle, False/True)
to just disable the parent form. At this point you can open multiple dialogs, but they can only be closed in last-in, first-out order, because the calls end up being recursive. If that's fine, stop here.
有两种方法可以解决这个问题:
There are two ways to work around that:
不是让
ShowModal
阻塞,而是让StartModal
和EndModal
例程具有 ShowModal 的代码的第一位和最后一位以及关闭对话框时调用OnShowModalDone
事件.这使用起来有点麻烦,但相对容易编码和稳定.
Rather than making
ShowModal
blocking, haveStartModal
andEndModal
routines that have the first bit and last bit of ShowModal's code and call anOnShowModalDone
event when the dialog is closed. This is kind of a pain to use, but is relatively easy to code and easy to make stable.
使用 Windows 纤程例程 交换堆栈并开始一个新的消息循环.这种方法很容易使用,因为 ShowModal
是阻塞的,所以你可以像往常一样调用它.这是我们在 Beyond Compare 中使用的方法.不要这样做.编写起来很复杂,由于与第三方代码(Windows 全局消息挂钩、TWebBrowser、.NET 在浏览对话框加载的 shell 扩展中等),如果它是一个跨平台项目,则 Unix ucontext 函数也不安全.
Use the Windows fiber routines to swap out the stack and start a new message loop. This approach is easy to use, because ShowModal
is blocking, so you call it like normal. This is the approach we used in Beyond Compare. Don't do it. It's complicated to write, there will be stability issues for non-trivial applications because of incompatibilities with third party code (Windows global message hooks, TWebBrowser, .NET in shell extensions loaded by the browse dialog, etc), and if it's a cross-platform project, the Unix ucontext functions aren't safe to use either.
常见的对话框(TOpenDialog、TColorDialog 等)也有类似的限制.要使它们只禁用父窗体,您需要覆盖 TCommonDialog.TaskModalDialog
并替换 DisableTaskWindows/EnableTaskWindows
调用.它们不能像上面的常规 Delphi 对话框那样异步,因为它们阻塞了 Windows 提供的功能 (GetOpenFileName, 选择颜色等).允许以任何顺序关闭的唯一方法是让每个对话框在专用线程中运行.只要您小心访问 VCL 对象,Windows 可以处理大部分同步操作,但它基本上涉及重写大部分 Dialogs.pas
.
The common dialogs (TOpenDialog, TColorDialog, etc), have similar restrictions. To make them only disable the parent form you need to override TCommonDialog.TaskModalDialog
and replace the DisableTaskWindows/EnableTaskWindows
calls there too. They can't be made asynchronous like the regular Delphi dialogs above though, since they're blocking functions provided by Windows (GetOpenFileName, ChooseColor, etc). The only way to allow those to close in any order is to have each dialog run in a dedicated thread. Windows can handle most of the synchronization to do that, as long as you're careful about accessing the VCL objects, but it basically involves rewriting large portions of Dialogs.pas
.
这篇关于Delphi,如何制作独立的窗口的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!