表格已经打开了吗?

6

我一直在使用以下代码来检查表单是否已存在:

function FormExists(apForm: TObject): boolean;
var i: Word;
begin
  Result := False;
  for i := 0 to Application.ComponentCount-1 do
    if Application.Components[i] = apForm then begin
      Result := True;
      Break;
    end;
end;

几年前,我参与的一个项目中得到了这个工具。当时是我做的第一个Delphi项目。

目前它还能正常运行。

但是最近我开始思考,是否有更好、更快的方法来实现这个功能。


1
这个函数是否曾经返回过 false?如果是,是在什么情况下?问这个问题是因为不清楚你所说的“存在”是什么意思。 - Sertac Akyuz
是的。如果表格没有被创建。 - Jlouro
好的,正如你在评论中已经提到的那样,只需测试“已分配”即可。 - Sertac Akyuz
1
@TLama - 我想我明白了。但是我不会在悬空指针上测试窗口句柄。我自己在OnDestroy中将全局变量赋值为nil。 - Sertac Akyuz
我真的无法理解为什么会有这么多争论和大量的代码,当你只需要一个aForm<>nil。 - David Heffernan
显示剩余3条评论
2个回答

13

你可以使用 Screen.Forms 来代替。这样可以减少需要迭代的项目:

function FormExists(apForm: TForm): boolean;
var 
  i: Word;
begin
  Result := False;
  for i := 0 to Screen.FormCount - 1 do
    if Screen.Forms[i] = apForm then 
    begin
      Result := True;
      Break;
    end;
end;

然而,值得注意的是,如果你已经有了apForm,你知道它存在,就不需要再去搜索它。


但事实如此。在某些情况下,我不知道该怎么办,对于其他情况,我使用“已指定”。 - Jlouro
@Jlouro,可以像Sertac说的那样将全局表单变量设置为nil,以使用Assigned测试,或者使用这种迭代方式。请求已释放控件变量的有效句柄是不安全的。 - TLama

-4

我发现最好的方法是询问表单本身是否已经打开,你可以使用一个 CLASS 程序/函数来实现。即使表单不存在,调用表单的类程序/函数也是安全的。

向表单的公共声明添加一个类函数即可。

  type
    TForm2 = class(TForm)
      ...
    private
      { Private declarations }
      ...
    public
      { Public declarations }
      class function FormExists:  Boolean;
    end;

  class function TForm2.FormExists: Boolean;
  var
     F: TForm2;
     I: Integer;
  begin
     F := nil;
     for i := Screen.FormCount - 1 DownTo 0 do
      if (Screen.Forms[i].Name = 'Form2') then
      begin
         F := Screen.Forms[I] As TForm2;
         break;
      end;
     Result :=  F <> nil;
  end;

因此,任何使用了Form2的单元都可以调用它。

     if Form2.FormExists then
        ...

2
-1. 这是完全错误的解决方案。它将您的代码与特定的表单名称绑定在一起。您永远不应该针对“Name”进行测试;这会使所有内容过于具体化,并使您的代码无法在其他地方重复使用。 - Ken White
这是一种简单直观的面向对象方法。表单对象本身可以告诉您它是否已经打开。而在您的方法中,您需要知道并提供有关所涉及表单的某些数据。我使用的这种方法的附加好处是,如果F不是nil,则是对表单本身的引用,您可以检查表单组件的状态。我用它来知道我正在处理的文档是否被修改,如果是,我将该表单移到前面,并向用户呈现保存选项。这是您的方法难以实现的东西。 - A Lombardo
3
将“Name = 'Form2'”硬编码作为引用就像在身体的某个私密部位纹上你第一个女朋友的名字。如果你总是约会同名的女人,那还好,但除此之外真的很糟糕。你永远不要硬编码一个名称引用 - 永远不要。你的代码是错误的。这与“面向对象”无关 - 硬编码对特定名称的引用是不良代码。它会破坏以下代码: var MyForm: TForm2; ... MyForm := TForm2.Create(nil); MyForm.Name := 'Mary';,你的代码将无法工作。 - Ken White
@KenWhite 这是在表单本身中硬编码的,您知道表单名称。 就像您编写 Edit1.Text := '...'; 一样。 - A Lombardo
4
在我看来,问题不在于硬编码的名称,而在于每个需要具备这种功能的表单类都必须重复复制相同的代码。在我看来,这正是“过程式”方法在这种情况下更好的原因。 - jpfollenius
显示剩余7条评论

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接