是否可以通过在运行时将其类名指定为字符串来创建控件?



而不是,

TButton *button = new TButton(MyForm);

一个人能做这样的事情吗?

TControl *control = new TControl(MyForm, "TButton");

在 Delphi 中,可以从 RTTI 创建给定类元类型的对象实例。毕竟,这正是DFM流在运行时所做的。

但在C++,你不能用RTTI做这样的事情。

因此,您必须:

  1. 让你的C++代码创建自己的字符串到函数映射查找表,其中函数调用适当的类构造函数,例如:
#include <string>
#include <map>
#include <functional>
std::map<std::string, std::function<TControl*(TComponent*)>> mymap;
...
mymap["TButton"] = [](TComponent *Owner) -> TControl* { return new TButton(Owner); };
...

或:

#include <string>
#include <map>
typedef TControl* (*CreateControlFunc)(TComponent*);
std::map<std::string, CreateControlFunc> mymap;
...
TControl* CreateButton(TComponent *Owner) { return new TButton(Owner); }
mymap["TButton"] = &CreateButton;
...

无论哪种方式,您都可以执行以下操作:

TControl *control = mymap["TButton"](MyForm);
  1. .pas单元中编写一个 Delphi 函数以按类名处理对象创建,然后将该文件添加到 C++Builder 项目中。编译项目时,将输出一个.hpp文件,您可以在C++代码中#include该文件。
unit CreateControlHelper;
interface
uses
Classes, Controls;
function CreateControlByClassName(const ClassName: String; Owner: TComponent): TControl;
implementation
function CreateControlByClassName(const ClassName: String; Owner: TComponent): TControl;
var
Cls: TPersistentClass;
begin
Cls := FindClass(ClassName);
if (Cls <> nil) and Cls.InheritsFrom(TControl) then
Result := TControlClass(Cls).Create(Owner)
else
Result := nil;
end;
end.
#include "CreateControlHelper.hpp"
TControl *control = CreateControlByClassName("TButton", MyForm);

更新:

  1. 理论上,你也可以使用增强型RTTI,因为它的实现是基于Delphi的,例如:
#include <System.Rtti.hpp>
TRttiMethod* FindControlConstructor(TRttiType *Type)
{
while (Type)
{
DynamicArray<TRttiMethod*> methods = Type->GetDeclaredMethods();
for(int i = 0; i < methods.Length; ++i)
{
TRttiMethod *method = methods[i];
if ((method->Name == "Create") && (method->IsConstructor))
{
DynamicArray<TRttiParameter*> params = method->GetParameters();
if ((params.Length == 1) && (params[0]->ParamType->Handle == __typeinfo(TComponent)))
{
return method;
}
}
}
Type = Type->BaseType;
}
return NULL;
}
TControl* CreateControlByClassName(const String &QualifiedClassName, TComponent *Owner)
{
TRttiContext ctx = TRttiContext::Create();
TRttiType *type = ctx.FindType(QualifiedClassName);
TRttiMethod *method = FindControlConstructor(type);
if (method)
{
TValue val;
val = Owner;
TValue res = method->Invoke(type->AsInstance()->MetaclassType, &val, 0);
return static_cast<TControl*>(res.AsObject());
}
return NULL;
}
TControl *control = CreateControlByClassName("Vcl.StdCtrls.TButton", MyForm);

最新更新