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

时间:2010-07-19 11:15:25

标签: delphi

我想在列表框中动态列出项目中存在的所有表单的名称,然后通过单击每个表单,列出该表单上另一个ListBox中存在的所有按钮。

但我不知道它是否可以实施以及如何实施。

请帮助我。

由于

6 个答案:

答案 0 :(得分:7)

如果您使用的是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;

您必须以某种方式注意链接器未完全删除该类(因此上面的注册提示)。否则你无法用上述方法获得该课程。

答案 1 :(得分:6)

表单通常使用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;

答案 2 :(得分:4)

sabri.arslan的答案是在运行时查找所有实例化表单的方法。

在评论中,哈米德要求找到未分配表格的方法。假设通过未分配,他意味着未实例化的表单,那么只有一种方法可以执行此操作,即迭代vcl流系统使用的类的注册表,以便在流式传输dfm时按名称实例化组件。

但是,IIRC,表单不会自动添加到注册表中。实际上,如果要基于其名称字符串实例化表单,则需要(ed)将它们自己添加到类注册表中。 OP当然可以为他自己项目中的每个表单做到这一点。但是,这留下了一个问题,即流系统使用的类注册表是使用类单元的实现部分中的var实现的。因此,不能从外部(轻松)迭代。

因此,解决方案是使用项目中所有表单单元的初始化部分,并将每个表单注册到“自己动手”的注册表中,并使用其名称和类,并让注册表提供迭代的方法。注册表格。这些方法可用于填充OP提到的列表框。

要获取表单上的TButtons,则需要实例化表单(它可能保持隐藏状态)并使用类似于sabri.arslan的答案的代码迭代组件以查找TButton实例。

实例化表单需要根据在列表框中选择的表单名称从注册表中获取表单的类。

简单的roll-your-own表单注册表示例:

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.

答案 3 :(得分:0)

你可以使用“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;

答案 4 :(得分:0)

找不到包含的表格是没有办法的。

但是,如果您遍历资源的RCdata(请参阅(1) (2) (3)),您可以找到表单的名称。但这并不能帮助你创造它们。

为了使表单“可查找”,必须自己“注册”它们,使用RegisterCLass og再次使用FindClass查找它们。请在此处查看示例:http://www.obsof.com/delphi_tips/delphi_tips.html#Button

答案 5 :(得分:0)

您是否需要在运行时构建它,或者编译时间信息对您有用吗?

在最新版本(Delphi 2006及更高版本?)中,您可以设置编译器选项以为项目生成XML文档。为每个单元生成单独的XML文件。您可以解析此XML以查找和表单,并查看任何按钮的成员。

相关问题