亲切的问候
Roy M Klever
解决方法
首先,您需要完全避免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替换为自定义版本.除此之外,该例程禁用了应用程序中的所有其他窗口,因此您需要使用EnableWindow(Owner.Handle,False / True)替换DisableTaskWindows / EnableTaskWindows调用以仅禁用父窗体.此时,您可以打开多个对话框,但它们只能以后进先出顺序关闭,因为调用最终是递归的.如果没关系,请停在这里.
>而不是使ShowModal阻塞,让StartModal和EndModal例程具有ShowModal代码的第一位和最后一位,并在关闭对话框时调用OnShowModalDone事件.这是一种使用起来很痛苦,但相对容易编码并且易于稳定.
>使用Windows fiber routines交换堆栈并启动新的消息循环.这种方法很容易使用,因为ShowModal是阻塞的,所以你可以像平常一样调用它.这是我们在Beyond Compare中使用的方法.不要这样做.编写起来很复杂,如果存在全局消息挂钩或者如果您的任何代码不是光纤安全的话,它可能会遇到麻烦.
>常见的对话框(TOpenDialog,TColorDialog等)也有类似的限制.要使它们只禁用父窗体,您需要覆盖TCommonDialog.TaskModalDialog并替换那里的DisableTaskWindows / EnableTaskWindows调用.它们不能像上面的常规Delphi对话那样异步,因为它们阻止了Windows(GetOpenFileName,ChooseColor等)提供的功能.允许那些以任何顺序关闭的唯一方法是让每个对话框在专用线程中运行.只要您小心访问VCL对象,Windows就可以处理大部分同步,但它基本上涉及重写Dialogs.pas的大部分内容.