【问题标题】:Delphi: Close all forms (except MainForm), but, ignore any OnCloseQuery dialogsDelphi:关闭所有表单(MainForm 除外),但忽略任何 OnCloseQuery 对话框
【发布时间】:2012-06-03 14:40:11
【问题描述】:

基本上,我使用TTimer 事件来关闭所有打开的表单并将用户带回主表单。 我可以遍历Screen.Forms

for i := 0 to Screen.Formcount - 1 do
  Screen.Forms[i].close;

问题是其中一些表单上的 OnCloseQuery 事件 - 它们弹出 MessageDlg 中断此过程:(

【问题讨论】:

  • 我试图避免不得不“破解”所有表单的“OnCloseQuery”事件。另外,当 MessageDlg 弹出时,这可以算作“新”表单,之前不在“关闭”循环中,因此必须手动关闭。
  • 如果他们因为某种原因中断了进程,那么他们不应该被关闭。如果他们没有理由不关闭,那么他们不应该中断进程(他们不应该设置“CanClose”)。
  • OnCloseQuery 事件经常包含 MessageDlgs 说“您确定要取消此活动吗?”是/否——我什至不想给他们这样的选择——我想在没有 OnCloseQuery 的情况下关闭。
  • 所以你问用户是否有理由不关闭。我只是确保有一个视觉指示表明有一个活动,其余的留给用户。但也许这只是我..
  • 看来你需要重构你的应用程序。 “关闭处理逻辑”可以委托给一个拥有它需要的所有信息的地方。比全局布尔破解要好得多。

标签: delphi delphi-7


【解决方案1】:

您可以在主表单中使用一个标志,其他表单会在询问用户是否继续之前检查该标志。像这样的:

单元1

type
  TForm1 = class(TForm)
    ..
  public
    UnconditinalClose: Boolean;
  end;

..

procedure TForm1.Timer1Timer(Sender: TObject);
begin
  UnconditinalClose := True;
end;

第 2 单元:

implementation

uses
  unit1;

procedure TForm2.FormCloseQuery(Sender: TObject; var CanClose: Boolean);
begin
  CanClose := unit1.Form1.UnconditinalClose;
  if not CanClose then
    // ask the user if he/she's sure he/she wants to close
end;


另一种解决方案可能是分离其他形式的OnCloseQuery 事件处理程序。 这只有在关闭时释放(释放)这些其他表单而不是隐藏时才实用(编辑以反映 Rob 的评论):

procedure TForm1.Timer1Timer(Sender: TObject);
var
  i: Integer;
  SaveHandler: TCloseQueryEvent;
begin
  for i := 0 to Screen.Formcount - 1 do
    if Screen.Forms[i] <> Self then begin
      SaveHandler := Screen.Forms[i].OnCloseQuery;
      Screen.Forms[i].OnCloseQuery := nil;
      Screen.Forms[i].Close;
      Screen.Forms[i].OnCloseQuery := SaveHandler;
    end;
end;

【讨论】:

  • 这是一个有用、实用的答案,谢谢,但它确实需要我处理每个表单的每一个 OnCloseQuery 事件——这是我想避免的。我不能以永远不会使用 OnCloseQuery 事件的方式释放/释放/销毁/关闭表单吗?
  • 回复:您的替代解决方案:看起来不错!...有趣的是,现在我回复了您,我几乎有点想到了,我已经玩了这个问题大约 5 个小时现在!这就是“结对编程”有效的原因:人们在与他人互动时会思考得更好。让我试一试,然后回复你,这可能正是我需要的
  • 到目前为止效果很好,谢谢!!!就像你说的那样,表单必须在之后被释放,并且这个应用程序就是这样编写的,所以它应该可以正常工作。根据我的谷歌搜索,我相信这个解决方案将来也会对其他人有用。再次感谢:D
  • @Richard - 不客气!我希望我没有冒犯你质疑你的设计。 :)
  • 第二个建议,即分离事件处理程序,即使在没有释放表单的情况下也是可行的。您只需在调用Close 后重新附加事件处理程序。即使关闭操作是caFree,这也是安全的,因为表单实际上不会立即被释放。在程序开始处理cm_Release 消息之前,它不会被释放,我们已经知道程序不会这样做,因为Screen.FormCount 在循环期间没有改变。
【解决方案2】:
for i := 1 to Screen.Formcount - 1 do
  Screen.Forms[i].close;

将 i 的值初始化为 1,而不是 0。

【讨论】:

  • 你能详细说明你的答案吗?特别说明为什么要从 1 开始。
  • @UwePlonus 我猜这将关闭除主表单之外的所有表单,即 Screen.Forms[0]。如果您关闭 man 表单,程序将终止,这不是您想要的。另一方面,这并不能回答问题,因为它仍然调用 OnCloseQuery 事件。
  • 第一个窗口是主窗体,值索引是0,第二个窗体是1,第三个是2 ...
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-02-25
  • 1970-01-01
  • 1970-01-01
  • 2012-01-13
  • 2012-01-08
  • 2023-02-16
相关资源
最近更新 更多