【问题标题】:Cancel / abort creating a new form in Delphi / C++Builder?取消/中止在 Delphi/C++Builder 中创建新表单?
【发布时间】:2009-08-31 15:42:44
【问题描述】:

有没有办法从表单的 OnCreate 事件处理程序或 C++Builder 构造函数中取消或中止表单创建?

基本上,我希望能够从 OnCreate 或构造函数调用 Close() 并让它完全跳过显示表单。我有几种形式,作为它们初始化的一部分,它们可能决定根本不应该显示它们。 (我意识到我可以将初始化的这一部分分开,或者从调用表单或类似的表单中添加额外的检查,但是如果有一种方法可以从 OnCreate 或构造函数中干净地完成所有这些工作,那似乎是最简单的。)

编辑:针对少数cmets,部分don't-show-at-all逻辑是UI逻辑而非业务逻辑;表单可能会在显示之前显示确认信息,或者它可能使用通用对话框来获取表单的输入,然后如果用户取消该对话框则中止。 (其中一些是业务逻辑,需要重构,但通常很难找到时间重构所有需要它的东西。)

【问题讨论】:

  • 嗨。您的架构可能是错误的。如果您只想关闭它,请不要创建表单。相反,将所有初始化代码移动到一个大/胖过程中(我们称之为 ApplicationInitialize)。在该过程中,您决定要创建或不创建哪些表单。通过向自己发布消息 (wm_AppStarted) 来调用该胖程序,如下所示:stackoverflow.com/questions/382527/…

标签: delphi forms c++builder


【解决方案1】:

您始终可以在OnCreate 处理程序中调用Release,但这会导致表单快速出现然后被关闭。不是很专业的东西。

所以这是另一个想法。让表单有一个公共函数或属性来返回它们是否实际上要显示。然后你通常会有的地方

TheForm := TSomeForm.Create(Self);
TheForm.Show;

你会的

TheForm := TSomeForm.Create(Self);
if TheForm.ShouldAppear then
  TheForm.Show
else
  TheForm.Release;

话虽如此 - 任何其他编码方式(因此您不会创建将立即销毁的表单)肯定更好。尤其是如果你想保持 UI 和业务层之间的清晰分离,最好有代码来决定表单是否显示在表单之外。仅在您做出决定后创建表单。

【讨论】:

  • 我明确回答了你的问题,没有使用例外,因为我认为这是一种滥用。如果表单显示的可能性与不显示的可能性一样,那么它没有什么特别之处。
  • Abort 异常是专门为此设计的。绝不是滥用。
  • “让表单有一个公共函数或属性来返回它们是否真的要显示”-我相信它已经存在并且被称为TForm.Visible :-D
  • @Arioch'The:所以你实际上会写if TheForm.Visible then TheForm.Show
  • @mghie 不,但我可能会写with TheForm do if not Visible then Release
【解决方案2】:

我认为甚至不必首先创建表单要好得多。如果您正在执行一些确定表单甚至不需要的逻辑,并且该逻辑包含对表单很重要的状态,则将逻辑重构为单独的对象(甚至是数据模块)并传递对象作为属性的形式。这是一个简单的例子(使用对象方法):

UNIT1

type
  TOFormTests = class
    fStateData : string;
  public
    function IsForm1Needed( someparam : string) : boolean;
    property StateData : string read fStateData write fStateData;
  end;

UNIT2

uses
  : 
  UNIT1;

type
  TForm1 = class(tForm)
  :
  procedure SetFormTests(value : tOFormTests);
  property FormTests : TOFormTests read fFormTests write SetFormTests;
end;

procedure SetFormTest(Value:TOFOrmTests);
begin
  fFormTests := Value;
  // perform gui setup logic here.
end;

然后在您的代码中的某个地方,您想要确定是否应该显示您的 gui 或不使用类似以下的内容:

var
  Tests : TOFormTests;
begin
  tests := tOFormTests.create;
  try
    if Tests.IsForm1Needed('state data goes here') then
      begin
        Form1 := tForm1.create(nil);
        try
          Form1.FormTests := Tests;
          if Form1.ShowModal = mrOk then
            // handle any save state logic here.
          ;
        finally
          FreeAndNil(Form1);
        end;
      end;
  finally
    freeAndNil(Tests);
  end;
end;

这也假设表单不在自动创建列表中,需要以模式显示。

【讨论】:

  • +1 我完全同意:这是业务逻辑,所以应该在创建表单之前确定。
  • 只有在您从一个地方调用表单时才会如此。如果您有可以从不同位置调用的表单,那么能够将逻辑放入表单中肯定更有意义(并且不必记住调用某些特定的例程来测试是否应该显示它)。但与许多主题一样,会有不同的阵营。
【解决方案3】:

在构造函数中使用Abort。它引发了一个静默异常。如果对象在构造函数中有异常,则调用析构函数并释放内存。 Abort 的优点是,如果不添加异常处理代码,则无需担心会显示异常对话框。

【讨论】:

  • 这行得通,但是在我看来,重写构造函数而不是添加 OnCreate 处理程序似乎有点矫枉过正,尤其是因为整个想法一开始就很臭。只是我的 0,02 欧元。
  • 我们在 C++Builder 中完成了大部分工作,其中重写构造函数优于添加 OnCreate 处理程序。
【解决方案4】:

添加一个在需要时返回实例的类函数。那么确定是否应该显示表单的方法仍然在那个类中,但是它可以在实际构造表单之前确定是否有必要。将其称为“CreateIfNeeded”,它将像构造函数一样工作,但如果不需要,它实际上不会构造表单。最少的代码更改和最大的灵活性。

【讨论】:

    【解决方案5】:

    只需在 OnCreate 中引发异常。 您还需要重新定义 HandleCreateException 方法的行为(默认是显示错误消息,而不是取消创建)。

    【讨论】:

      【解决方案6】:

      我会覆盖 ShowModal

      function TfHtmlEditor.ShowModal: Integer;
      begin
        if TabControl1.Tabs.Count=0 then
          Result := mrAbort
        else
          Result := inherited;
      end;
      

      【讨论】:

        猜你喜欢
        • 2013-01-01
        • 1970-01-01
        • 1970-01-01
        • 2011-05-08
        • 1970-01-01
        • 2013-05-05
        • 2012-08-07
        • 1970-01-01
        • 2016-06-22
        相关资源
        最近更新 更多