【问题标题】:Delphi Form Creation and ShowingDelphi 表单创建和显示
【发布时间】:2014-08-18 20:14:44
【问题描述】:

我正在尝试在 Delphi XE6 中创建一个包含 2 个表单的应用程序。根据ParamStr 设置,Form2 可能会或可能不会在 Form1 之前显示。

在快速测试应用中,两个表单都是在调用 Form1.Show 之前创建的 - 在此期间是否显示 Form2

procedure TForm1.FormShow(Sender: TObject);
begin
  if ParamStr(1) = 'foo' then
      Form2.FooShow;
end;

procedure TForm2.FooShow;
begin
   ShowModal;
end;

但是在“真实”应用程序中我看到了不同的行为。

在这种情况下,只要调用 Application.CreateForm(TForm1, Form1),就会调用 Form1.Show。这是创建 Form2 之前,这会导致问题,因为 Form2 在需要时不存在。

任何解释为什么行为会有所不同?我是否错过了隐藏在 Project>Options

中某处的设置

【问题讨论】:

  • 我已经使用新的 Forms 重新创建了应用程序,现在它的行为符合预期 - 似乎有一个设置潜入到原来的某个地方
  • 正如我在answer 中指出的那样:“潜入”的设置是Form1 上的Visible 属性。我怀疑您是否编写了额外的代码来在创建时显式显示表单,否则您会更轻松地解决问题。这留下了唯一会导致表单在创建后立即显示的情况是,如果在设计时属性 Visible = True
  • Visible 在应用程序的“工作”版本中设置为 true。
  • 您声称:“Visible 在应用程序的“工作”版本中设置为 true。”说白了就是绝对垃圾!除非您忽略了有关“工作”快速测试的非常重要的事情,否则转到Form1 并在设计时属性编辑器中设置Visible=True 将导致访问冲突TForm1.FormShow 尝试显示Form2 时。我只能假设您错误地认为 Visible 是真的,因为 Form1 在您运行应用程序时自动显示。 提醒:主窗体始终自动显示,即使 Visible 为 false。
  • Dan,认真地尝试在您的问题中按照您自己的说明并且Form1设计时的属性编辑器。您将观察到:(1) Form1 在创建后立即显示。 (2) 即在创建 Form2 之前。 (3) 如果TForm1.FormShow 尝试显示Form2,这将导致访问冲突。

标签: forms delphi delphi-xe6


【解决方案1】:

如果您的表单在 Visible 设置为 True 的情况下保持不变,那么它将在创建后立即显示。

将属性设置为 False 应该可以解决您的问题。

编辑

PS:以防万一有类似问题的人意外显示其主窗体,即使 Visible 设置为 False。发生这种情况是因为默认情况下,应用程序将显示主窗体,而不管其在对 Application.Run 的调用中的 Visible 属性如何。
如果是这样,以下问题应该会有所帮助:How can I start Delphi application with the hidden main form?

EDIT2

为了完整起见,还有一些其他因素可能会导致表单在创建后立即显示。但是,这些可能不适用于这个特定的问题。

  • 任何在创建表单时显式显示表单的代码(例如OnCreate 事件)显然会导致表单显示。但是,人们希望此类行为不会导致此类问题。
  • 永远不能隐藏 MDI 子窗体。充其量可以将其最小化。

提示

找到此类问题答案的最快方法通常只是进行一点调试。

  • FormShow 方法中设置断点。
  • 转到编译器设置,并启用使用调试 DCU 构建的选项。 (您会想查看 VCL 代码。)
  • 重建并运行您的应用程序。
  • 当您到达断点时,打开调用堆栈调试窗口。
  • 导航调用堆栈以查找触发器。

在这种情况下,您应该在Forms.pas 中找到以下代码。

procedure TCustomForm.DoCreate;
begin
  //...
  if fsVisible in FFormState then Visible := True; //<-- The trigger
end;

fsVisible 进行更多研究将揭示根本原因:Visible 属性设置为True


也就是说,您不想以这种方式编码,因为您正在通过全局变量创建依赖项。这很容易出错;你的小实验显示了许多可能导致问题的微妙事物中的一种。

宁可避免全局变量,在 DPR 中进行如下更改:

begin
  Application.Initialize;
  ShowForms;
end;

ShowForms 的实现方式为:

procedure ShowForms;
var
  LForm1: TForm1;
  LForm2: TForm2;
begin
  Application.CreateForm(TFrom1, LForm1);
  Application.CreateForm(TFrom2, LForm2);

  if (ParamStr(1) = 'foo') then
    LForm2.Show
  else
   LForm1.Show;
end;

如果表单之间没有任何依赖关系,以上就足够了。 如果您确实有依赖关系,例如Form2 使用 Form1:然后您可以在创建表单后显式传递引用,但在开始对它们进行任何操作之前。

//Define a property on TForm2 E.g.
property MainForm: TForm1 read FMainForm write SetMainForm;

//Immediately after creating both forms tell form2 which to use as its main form.
LForm2.MainForm := LForm1;

【讨论】:

  • 谢谢克雷格。这是在主窗体的 OnShow 期间设置为 Showmodal 的辅助窗体,但通常为 Visible = False
  • @DanKelly 您的评论让我怀疑您是否理解我的回答?您问为什么您的作品 Form1 在创建后会立即显示。 如果它在设计时设置为Visible = True。我唯一一次提到您的辅助表单是在我的回答的第二部分中,提出了一种不太容易出错的方法来确定是否显示 Form2。 IE。即使Form1 在创建后立即显示,也不会触发 AV。
  • 在应用程序的“工作”版本中,Form1 仅显示(我希望如此)Form2(显示模态)已被关闭。
猜你喜欢
  • 2010-11-05
  • 2018-10-02
  • 1970-01-01
  • 2021-04-28
  • 2021-01-15
  • 2011-03-06
  • 1970-01-01
  • 2017-06-20
  • 1970-01-01
相关资源
最近更新 更多