但是我不知道这是否可以实现以及如何实现。
如果您使用的是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”提示)。否则,你将无法使用所描述的方法获取该类。
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;
sabri.arslan的回答是在运行时查找所有已实例化表单的方法。
在评论中,Hamid要求找到未分配的表单。假设他指的是未实例化的表单,那么唯一的方法就是遍历VCL流媒体系统使用的类注册表,通过名称实例化组件,当DFM被流式传输时。
然而,我记得,表单并没有自动添加到注册表中。事实上,如果您想根据名称字符串实例化表单,您需要自己将它们添加到类注册表中。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.
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;
Screen.Forms
读取表单列表,而不是 Application.Components
。 - Rob Kennedy很难(容易)找到包含的表单。
但是,如果您循环遍历资源的RCdata(请参见(1) (2) (3)),则可以找到表单的名称。但这并不能帮助您创建它们。
为了使表单“可查找”,您必须自己“注册”它们,使用RegisterCLass或使用FindClass再次找到它们。在此处查看示例:http://www.obsof.com/delphi_tips/delphi_tips.html#Button