delphi 动态列出项目中的所有表单

vom3gejh  于 2022-12-12  发布在  其他
关注(0)|答案(6)|浏览(155)

我想在一个列表框中动态地列出我项目中所有窗体的名称,然后通过单击每个窗体,在另一个列表框中列出该窗体上存在的所有按钮。
但我不知道它是否可以实施,以及如何实施。

huus2vyu

huus2vyu1#

如果你在 Delphi 2010上,你可以使用RTTI来列出所有注册的(=在应用程序中以某种方式使用的)表单类:

uses
  TypInfo, RTTI;

procedure ListAllFormClasses(Target: TStrings);
var
  aClass: TClass;
  context: TRttiContext;
  types: TArray<TRttiType>;
  aType: TRttiType;
begin
  context := TRttiContext.Create;
  types := context.GetTypes;
  for aType in types do begin
    if aType.TypeKind = tkClass then begin
      aClass := aType.AsInstance.MetaclassType;
      if (aClass <> TForm) and aClass.InheritsFrom(TForm) then begin
        Target.Add(aClass.ClassName);
      end;
    end;
  end;
end;

你必须注意这个类不能被链接器完全删除(因此上面的 registered 提示),否则你不能用描述的方法得到这个类。

aemubtdh

aemubtdh2#

窗体通常使用Screen.Forms属性列出,例如:

procedure TForm1.Button1Click(Sender: TObject);
var
  I: Integer;

begin
  Memo1.Lines.Clear;
  for I:= 0 to Screen.CustomFormCount - 1 do
    Memo1.Lines.Add(Screen.Forms[I].Caption);
end;
qeeaahzv

qeeaahzv3#

arslan的答案是在运行时找到所有示例化的表单。
在评论中,Hamid也要求找到未赋值的表单。假设他所说的未赋值是指未示例化的表单,那么只有一种方法可以做到这一点,那就是在vcl流系统使用的类注册表中迭代,当dfm被流入时,按名称示例化组件。
但是,IIRC表单不会自动添加到注册表中。OP当然可以自己为项目中的每一个窗体添加这些窗体,但是,这留下了这样的问题,即流式传输系统所使用的类注册表是使用类单元的实现部分中的var来实现的。因此不能(轻易地)从外部进行迭代。
因此,解决方案是使用项目中所有表单单元的初始化部分,在“roll-your-own”注册表中注册每个表单,并使用它们的名称和类,让注册表提供迭代已注册表单的方法。这些方法可用于填充OP提到的列表框。
要获得表单上的TButton,需要示例化表单(它可能保持隐藏),并使用类似sabri.arslan的代码迭代组件,以找到TButton示例。
示例化窗体需要根据在列表框中选择的窗体名称从注册表中获取窗体的类。
一个简单的自卷窗体注册表示例:

unit Unit1;

interface

uses
  Classes
  , Forms
  , SysUtils
  ;

  procedure RegisterForm(aName: string; aClass: TFormClass);
  procedure ListForms(aNames: TStrings);
  function InstantiateForm(aName: string): TCustomForm;

implementation

var
  FormRegistry: TStringList;

procedure RegisterForm(aName: string; aClass: TFormClass);
begin
  FormRegistry.AddObject(aName, Pointer(aClass));
end;

procedure ListForms(aNames: TStrings);
var
  i: Integer;
begin
  for i := 0 to FormRegistry.Count - 1 do begin
    aNames.Add(FormRegistry[i]);
  end;
end;

function InstantiateForm(aName: string): TCustomForm;
var
  idx: Integer;
  frmClass: TFormClass;
begin
  Result := nil;
  idx := FormRegistry.IndexOf(aName);
  if idx > -1 then begin
    frmClass := TFormClass(FormRegistry.Objects[idx]);
    Result := frmClass.Create(nil);
  end;
end;

initialization
  FormRegistry := TStringList.Create;
  FormRegistry.Duplicates := dupError;
  FormRegistry.Sorted := True;
finalization
  FreeAndNil(FormRegistry);
end.
xkrw2x1b

xkrw2x1b4#

您可以使用“for”循环。

procedure ListForms(lbForms:TListBox);
var
  i,j:integer;
begin
         for i:=0 to application.ComponentCount-1 do
          if application.components[i] is tform then
          begin
           lbForms.add(tform(application.components[i]).Name);
          end;
end;

procedure ListBox1Click(Sender:TObject);
var
 ix,j,i:integer;
begin
 ix:=ListBox1.ItemIndex;
 if ix>=0 then
 begin
  for i:=0 to application.componentcount-1 do
   if application.components[i] is tform then
   begin
    if tform(application.components[i]).name=listbox1.items.strings[ix] then
    begin
     for j:=0 to tform(application.components[i]).controlcount - 1 do
      if tform(application.components[i]).controls[i] is tbutton then
      begin
       listbox2.add(tbutton(tform(application.components[i]).controls[i]).caption);
      end;
     break;
    end;
   end;
 end;
end;
aelbi1ox

aelbi1ox5#

没有办法(容易)找到包含的表格。
但是如果你遍历资源的RCdata(参见(1)(2)(3)),你可以找到表单的名称,但是这并不能帮助你创建表单。
为了使表单“可查找”,必须自己“注册”它们,使用RegisterCLAass,然后使用FindClass再次查找它们。请参见此处的示例:http://www.obsof.com/delphi_tips/delphi_tips.html#Button

kyxcudwk

kyxcudwk6#

您是否需要在运行时构建此信息,或者编译时信息是否对您有用?
在最近的版本( Delphi 2006和更高版本?)中,您可以设置编译器选项来为项目生成XML文档。为每个单元生成一个单独的XML文件。您可以解析此XML以查找和表单,并查看任何按钮的成员。

相关问题