gpt4 book ai didi

delphi - 如何从非模式窗体显示模式对话框?

转载 作者:行者123 更新时间:2023-12-03 14:43:53 27 4
gpt4 key购买 nike

我有两个“无模式”表单:

  • 一个是特殊的MainForm
  • 另一个是无模式形式

enter image description here

您可以看到:

  • 两者都存在于任务栏上
  • 两者都有一个任务栏按钮
  • 两者都可以独立最小化
  • 两者都可以独立恢复
  • 两者都不总是位于对方之上(拥有)

现在显示模态表单

从这个无模式表单中,我想显示一个模态表单:

enter image description here

Modal 表单的构造如下:

var
frmExchangeConfirm: TfrmExchangeConfirm;
begin
frmExchangeConfirm := TfrmExchangeConfirm.Create(Application);
try
//Setting popupMode and popupParent still makes the MainForm disabled
// frmExchangeConfirm.PopupMode := pmExplicit;
// frmExchangeConfirm.PopupParent := Self; //owned by us

frmExchangeConfirm.OwnerForm := Self; //tell the form which owner to use
frmExchangeConfirm.ShowModal;
finally
frmExchangeConfirm.Free;
end;

通过新的 OwnerForm 属性告知模态表单要使用哪个所有者:

protected
procedure SetOwnerForm(const Value: TForm);
public
property OwnerForm: TForm read GetOwnerForm write SetOwnerForm;
end;

强制重新创建句柄:

procedure TfrmExchangeConfirm.SetOwnerForm(const Value: TForm);
begin
FOwnerForm := Value;

if Self.HandleAllocated then
Self.RecreateWnd;
end;

然后是第二次通过CreateParams:

procedure TfrmExchangeConfirm.CreateParams(var Params: TCreateParams);
begin
inherited;

if FOwnerForm <> nil then
Params.WndParent := FOwnerForm.Handle;
end;

问题是:

  • 一旦显示此拥有的模态表单,我就无法与MainForm交互
  • 我无法使用任务栏按钮最小化MainForm
  • 我无法使用任务栏按钮最小化模态框或其所属父级
  • 如果我使用最小化按钮最小化模态表单,MainForm就会消失
  • 我可以使用其任务栏按钮激活MainForm;但我无法与它互动

在过去的十年里,我已经问过这个问题大约 7 次了。上次我被 promise 将主窗体设为 MainForm 可以解决所有问题。

奖励:自 .NET 1.0 以来,WinForms 已正确处理此问题。

对于什么是模态对话框存在很多困惑。当您必须先与其交互才能继续使用其所有者之前,对话框就是模态对话框。来自 Windows Interface Design Guidelines :

Dialog boxes have two fundamental types:

  • Modal dialog boxes require users to complete and close before continuing with the owner window. These dialog boxes are best used for critical or infrequent, one-off tasks that require completion before continuing.
  • Modeless dialog boxes allow users to switch between the dialog box and the owner window as desired. These dialog boxes are best used for frequent, repetitive, on-going tasks.

Windows 有一个“所有者”的概念。当一个窗口被“拥有”时,它将始终显示在其所有者的顶部。当窗口是“模态”时,这意味着所有者被禁用,直到模态任务完成。

您可以在 ProgressDialog 中看到此效果API:

HRESULT StartProgressDialog(
[in] HWND hwndParent,
IUnknown *punkEnableModless,
DWORD dwFlags,
LPCVOID pvReserved
);

hwndParent [in]
Type: HWND
A handle to the dialog box's parent window.

dwFlags
Type: DWORD
PROGDLG_MODAL
The progress dialog box will be modal to the window specified by hwndParent. By default, a progress dialog box is modeless.

当然,你可能会很刻薄,并禁用所有其他窗口

  • 在话题中<​​/li>
  • 流程
  • 或系统

但我想要有正确的行为。我想做的是:

  • Windows 的用途
  • Office 应用程序的用途
  • Beyond Compare 的作用
  • WinForms 的作用
  • WPF 的作用
  • 我用过的每个应用程序的用途
  • 以及用户的期望

自 1998 年以来,我就希望在我的 Delphi 应用程序中使用此功能;当意识到 Delphi 3 不能正确支持 Windows 95 和任务栏时。

最佳答案

ShowModal 禁用同一线程中的所有其他顶级窗口。这包括您的主要表单。

您必须巧妙地显示此表单,使其按照您想要的方式运行。执行以下操作:

  1. 禁用无模式所有者表单。
  2. 通过调用 Show 显示“模态”表单。
  3. 当“模态”表单关闭时,启用无模态所有者。确保在“模式”表单的窗口被销毁之前启用所有者,如下所述。

您可以在步骤 2 和 3 之间运行您自己的模态消息循环,如 ShowModal 所做的那样,但这可能有点过头了。我只是显示表单为无模式,但禁用其所有者,使其相对于该所有者为“模态”。

这个过程有点微妙。查看 ShowModal 的源代码以获取灵感。此外,雷蒙德有关情态的史诗系列文章也是必读之物。我在这里链接到所有内容:Why does a MessageBox not block the Application on a synchronized thread?

雷蒙德提供的更多信息:The correct order for disabling and enabling windows :

When you destroy the modal dialog, you are destroying the window with foreground activation. The window manager now needs to find somebody else to give activation to. It tries to give it to the dialog's owner, but the owner is still disabled, so the window manager skips it and looks for some other window, somebody who is not disabled.

That's why you get the weird interloper window.

The correct order for destroying a modal dialog is

  • Re-enable the owner.
  • Destroy the modal dialog.

This time, when the modal dialog is destroyed, the window manager looks to the owner and hey this time it's enabled, so it inherits activation.

No flicker. No interloper.

关于delphi - 如何从非模式窗体显示模式对话框?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/31705874/

27 4 0
Copyright 2021 - 2024 cfsdn All Rights Reserved 蜀ICP备2022000587号
广告合作:1813099741@qq.com 6ren.com