2010-07-19 27 views
4

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

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

请帮帮我。

感谢

回答

4

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

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

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

因此,解决方案是使用项目中所有表单单元的初始化部分,并将每个表单注册到“自己的卷”注册表中,并注册其名称和类,并让注册表提供迭代方法注册表格。这些方法可以用来填充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. 
+0

非常感谢您亲爱的Marjan!你的解决方案对我非常有帮助。我亲你!!! – Hamid 2010-07-22 06:13:37

+3

@哈米德:而不是亲吻我,你会考虑接受(点击复选标记)这个答案吗? :-) – 2010-07-22 06:13:39

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; 
+0

是的。但它只返回指定的组件。我想列出我的项目中包括分配和未分配的所有表单。 – Hamid 2010-07-19 12:10:58

+0

我想,没有办法找到未分配对象的列表。 – histrio 2010-07-19 13:13:35

+1

*组件*未分配; *变量*是。另外,不用'Application.Components'来获取表单列表,可以考虑阅读'Screen.Forms'。 – 2010-07-19 13:23:01

0

没有办法(容易)找到包含的表单。

但是,如果您循环访问资源的RC数据(请参阅(1)(2)(3)),您可以找到表单的名称。但是这无助于你创造它们。

为了让表单“可找到”必须自己“注册”它们,使用RegisterCLass og再次使用FindClass查找它们。在这里看到一个例子:http://www.obsof.com/delphi_tips/delphi_tips.html#Button

+0

使用RegisterClass可以工作,但不幸的是,您无法迭代注册的类。所以你无法填充列表框。而FindClass以一个名字作为参数来返回相应的类类型。如果没有自己的注册机构进行注册并稍后发现已注册的表单名称,则会被卡住。 – 2010-07-19 13:33:57

+0

啊,我现在看到你通过RCData找到了表格的名字。一读时错过了。抱歉。 – 2010-07-19 13:44:33

+0

给定名称并假定该类不会被链接器删除,您可以使用“FindClass”创建这样的表单。 – 2010-07-19 13:55:28

6

的形式使用屏幕通常上市。窗体属性,例如:

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; 
7

如果你是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; 

你必须设法照顾这个类没有被链接器完全删除(因此上面的注册了提示)。否则,您无法使用所描述的方法来处理该类。

+0

Uwe Raabe,行: >'context:= TRttiContext.Create'是不必要的,不是吗?这是一个记录。 – 2011-10-28 11:47:44

+0

@Rafael:不,创建实际上需要初始化上下文。否则,您最终会收到未初始化的记录。 – 2011-11-01 09:37:05

0

你是否需要在运行时建立这个,或者编译时间信息为你工作?

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