我想在列表框中动态列出项目中存在的所有表单的名称,然后通过单击每个表单,列出该表单上另一个ListBox中存在的所有按钮。
但我不知道它是否可以实施以及如何实施。
请帮助我。
由于
答案 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以查找和表单,并查看任何按钮的成员。