【问题标题】:How do I close open OLE dialogs如何关闭打开的 OLE 对话框
【发布时间】:2012-04-24 08:33:08
【问题描述】:

我有一个功能可以关闭应用程序中除主窗体之外的所有窗体

procedure CloseOpenForms(const Component: TComponent);
var
  i: Integer;
begin
  for i := 0 to pred(Component.ComponentCount) do
  begin
    CloseOpenForms(Component.Components[i]);

    if Component.Components[i] is TForm then
    begin
      TForm(Component.Components[i]).OnCloseQuery := nil;

      TForm(Component.Components[i]).Close;
    end;
  end;
end;

从主窗体调用:

CloseOpenForms(Self);

只要没有活动的 OLE 对话框(例如 TJvObjectPickerDialog),它就可以正常工作。

如何强制关闭这些非模态 OLE 对话框?

【问题讨论】:

  • TJvObjectPickerDialog 例如实现了IDsObjectPicker 接口,它没有任何取消显示对话框的方法(仅仅是因为它旨在显示为没有 的模式对话框从其他地方取消选项)。我的猜测是,不可能以干净的方式做到这一点(如果有办法的话)。
  • 您是如何创建表单的?我打赌你没有使用Application.CreateForm
  • 正确。每个表单都在需要时创建:AForm := TMyForm.Create(Self)
  • 您必须让Application 成为表单的所有者才能使其正常工作。因此,对于您的情况,它将是 AForm := TMyForm.Create(Application)

标签: windows delphi ole jedi


【解决方案1】:

JVCL 将应用程序句柄传递给 IDSObjectPicker.InvokeDialog 的 'hwndParent' 参数,因此对话框由应用程序窗口拥有(不像 VCL 中的“所有者”,而是更像弹出父级) .然后,您可以对窗口进行枚举以找出应用程序窗口所拥有的窗口,并向它们发送关闭命令。

procedure CloseOpenForms(const AComponent: TComponent);

  function CloseOwnedWindows(wnd: HWND; lParam: LPARAM): BOOL; stdcall;
  begin
    Result := TRUE;

    if (GetWindow(wnd, GW_OWNER) = HWND(lParam)) and (not IsVCLControl(wnd)) then
    begin
      if not IsWindowEnabled(wnd) then      // has a modal dialog of its own
        EnumWindows(@CloseOwnedWindows, wnd);

      SendMessage(wnd, WM_CLOSE, 0, 0);
    end;
  end;

  procedure CloseOpenFormsRecursive(const RecComponent: TComponent);
  var
    i: Integer;
  begin
    for i := 0 to pred(RecComponent.ComponentCount) do
    begin
      CloseOpenFormsRecursive(RecComponent.Components[i]);

      if RecComponent.Components[i] is TForm then
      begin
        TForm(RecComponent.Components[i]).OnCloseQuery := nil;

        TForm(RecComponent.Components[i]).Close;
      end;
    end;
  end;

begin
  EnumWindows(@CloseOwnedWindows, Application.Handle);

  CloseOpenFormsRecursive(AComponent)
end;

【讨论】:

  • 我们越来越近了 :o) 如果 OwnedWindow 没有打开任何额外的窗口,上面的代码就可以工作。如果有(例如单击 ObjectPicker 窗口中的高级),则不会关闭任何窗口。
  • 此外,对于 CloseOpenForms 的每次迭代,原始代码都称为 EnumWindows。我做了一些修改来修复它。
  • 我想我成功了。我添加了代码以递归调用 CloseOwnedWindows 来关闭孩子的所有孩子。不幸的是,它只有在 Application.ProcessMessages 调用在那里时才能正常工作。如果您能想到更好的方法,请删除它。
  • @norge - 抱歉,我没有仔细看代码的作用。您的修改与我提出的相同。我认为在这里摆脱“Application.ProcessMessages”并不容易。感谢您的编辑!
  • @norge - 因为编译器觉得它必须传递一些隐藏/隐式参数作为第一个参数。看到这个问题:stackoverflow.com/questions/10162749/…
猜你喜欢
  • 1970-01-01
  • 2012-11-10
  • 1970-01-01
  • 1970-01-01
  • 2015-12-30
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2020-07-25
相关资源
最近更新 更多