Qt QMetaObjects 和从 QWidget 到 QObject 的转换
Posted
技术标签:
【中文标题】Qt QMetaObjects 和从 QWidget 到 QObject 的转换【英文标题】:Qt QMetaObjects and casting from QWidget to QObject 【发布时间】:2013-08-21 14:46:48 【问题描述】:我正在尝试编写读取 xml 文件并从此 xml 反序列化各种 qt 控件的代码,并且我使用 QDomDocument 执行此操作,我想从我的反序列化方法中获取 QLlist。我遇到了一些麻烦,这里是模板类(.h)文件的一些代码:
QList<T*> deserialize(QIODevice *input)
QList<T*> objects = QList<T*>();
if(_deserializeObject(input, objects))
return objects;
bool _deserializeObjects(QIODevice* input, QList<QObject*>& list);
还有我的.cpp文件和反序列化方法,这里我从文件中读取控制标签:
bool Serializer::_deserializeObjects(QIODevice* input, QList<QObject *> &objects)
QDomDocument doc;
if (!doc.setContent(input))
return false;
QDomElement root= doc.documentElement();
for(int j = 0; j < root.childNodes().length();j++)
QObject* object;
qDebug() << root.tagName();
if(root.tagName().contains("QGroupBox")) // <------- Here i need to determine which control i need to process.
????
qDebug () << object->metaObject()->className();
qDebug() << object->metaObject()->propertyCount();
for(int i = 0; i < object->metaObject()->propertyCount(); i++)
object->metaObject()->cast()
QMetaProperty prop = object->metaObject()->property(i);
QString propName = prop.name();
if(propName == "objectName")
continue;
QDomNodeList nodeList = root.elementsByTagName(propName);
if(nodeList.length() < 1)
continue;
QDomNode node = nodeList.at(0);
QVariant value = object->property(propName.toLatin1().data());
QString v = node.toElement().text();
if(propName == "x")
x = v.toInt();
else if(propName == "y")
y = v.toInt();
else if(propName == "width")
width = v.toInt();
else if(propName == "height")
height = v.toInt();
if(propName == "geometry")
continue;
object->setProperty(propName.toLatin1().data(), QVariant(v));
object->setProperty("geometry",QVariant(QRect(x,y,width,height)));
objects.push_back(object);
return true;
在这部分
if(root.tagName().contains("QGroupBox")) // <------- Here i need to determine which control i need to process.
????
qDebug () << object->metaObject()->className();
qDebug() << object->metaObject()->propertyCount();
for(int i = 0; i < object->metaObject()->propertyCount(); i++)
...
我想实际上以某种方式通过名称获取控件的类型,所以问题是,我可以将 QGroupBox 转换为 QObject 保存 QGroupBox 属性,以便 QObject 元对象类名称为 QGroupBox,所以我可以传递所有这些属性吗?因为我不想为每种控件类型制作循环。当我得到这样的结果时,我也是:
QList<QObject *> ds = s.deserialize<Object>((QIODevice*)&f);
然后我可以在一个循环中传递所有 QObject 并使用 QMetaObject 类名并使用 qobject_cast 将每个对象强制转换为 QPushButton、QLabel 等吗?
【问题讨论】:
【参考方案1】:QGroupBox 是 QObject 的子类;因此每个 QGroupBox 也是一个 QObject,所以你可以随时把它当做一个。不需要显式强制转换。
在循环中遍历所有不同的对象-派生自-QObject 将做您想做的事,前提是您调用它们的方法是虚拟方法(它们可能是--特别是 QObject::metaObject () 是一个虚方法,因此您的循环将返回适当的 QMetaObject,即使它是通过 QObject 指针调用它们的方法。
(顺便说一句,该过程中令人讨厌的部分可能是您从 XML 中读取对象类型名称的部分,现在需要实例化该类型的对象。AFAIK 没有好的自动方法在 C++ 中做到这一点,所以你能做的最好的事情是一个工厂函数,其中包含一个巨大的 switch 语句,为你可能想要实例化的每种类型都有一个单独的 case)
【讨论】:
所以应该是这样的吧?if(nodeName.contains("QPushButton")) QPushButton *btn = new QPushButton(); object = btn;
可能更像:QObject * obj = NULL; if (nodeName == "QPushButton") obj = new QPushButton;否则 if (nodeName == "QGroupBox") obj = new QGroupBox;否则 [...]
我还有一个问题,我可以在不同的线程中以某种方式创建我的反序列化对象吗?由于循环等原因,ui 线程中的反序列化冻结了我的 UI。我是否有可能以某种方式在不同的线程中创建 QPushButton/QLabel,然后将它们分配给我的 gui?
我不这么认为(见***.com/questions/13184555/…)。更好的方法是弄清楚为什么您的反序列化例程执行时间如此之长,并使其更快。分析是您的朋友。【参考方案2】:
或者,为正确的工作使用正确的工具。您真正在这里构建的可能是一些用于定义小部件布局等的 XML 东西。Qt 已经有一个工具,Qt Designer 它使用XML format 来定义 UI 和C++ code generator 用于在编译期间实际生成 C++ 代码。
【讨论】:
诀窍是我想在我的程序工作时将我的 xml 从服务器动态加载到程序中。以上是关于Qt QMetaObjects 和从 QWidget 到 QObject 的转换的主要内容,如果未能解决你的问题,请参考以下文章
尝试在vscode中运行qt时出现Blady放置()的错误[重复]