我想列出我的项目中存在的所有表单的名称,在列表框中动态显示,然后通过点击其中每个列表,在另一个列表框中列出该表单上存在的所有按钮。动态列出项目中的所有表格
但我不知道它是否可以实施以及如何实施。
请帮帮我。
感谢
我想列出我的项目中存在的所有表单的名称,在列表框中动态显示,然后通过点击其中每个列表,在另一个列表框中列出该表单上存在的所有按钮。动态列出项目中的所有表格
但我不知道它是否可以实施以及如何实施。
请帮帮我。
感谢
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.
您可以使用 “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;
没有办法(容易)找到包含的表单。
但是,如果您循环访问资源的RC数据(请参阅(1)(2)(3)),您可以找到表单的名称。但是这无助于你创造它们。
为了让表单“可找到”必须自己“注册”它们,使用RegisterCLass og再次使用FindClass查找它们。在这里看到一个例子:http://www.obsof.com/delphi_tips/delphi_tips.html#Button
使用RegisterClass可以工作,但不幸的是,您无法迭代注册的类。所以你无法填充列表框。而FindClass以一个名字作为参数来返回相应的类类型。如果没有自己的注册机构进行注册并稍后发现已注册的表单名称,则会被卡住。 – 2010-07-19 13:33:57
啊,我现在看到你通过RCData找到了表格的名字。一读时错过了。抱歉。 – 2010-07-19 13:44:33
给定名称并假定该类不会被链接器删除,您可以使用“FindClass”创建这样的表单。 – 2010-07-19 13:55:28
的形式使用屏幕通常上市。窗体属性,例如:
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;
如果你是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;
你必须设法照顾这个类没有被链接器完全删除(因此上面的注册了提示)。否则,您无法使用所描述的方法来处理该类。
Uwe Raabe,行: >'context:= TRttiContext.Create'是不必要的,不是吗?这是一个记录。 – 2011-10-28 11:47:44
@Rafael:不,创建实际上需要初始化上下文。否则,您最终会收到未初始化的记录。 – 2011-11-01 09:37:05
你是否需要在运行时建立这个,或者编译时间信息为你工作?
在最近的版本(Delphi 2006及更高版本?)中,您可以设置一个编译器选项来为您的项目生成XML文档。为每个单元生成一个单独的XML文件。你可以解析这个XML来查找和形成并查看任何按钮的成员。
非常感谢您亲爱的Marjan!你的解决方案对我非常有帮助。我亲你!!! – Hamid 2010-07-22 06:13:37
@哈米德:而不是亲吻我,你会考虑接受(点击复选标记)这个答案吗? :-) – 2010-07-22 06:13:39