QML/QT 如何将对象从 C++ 转换为 QML?
Posted
技术标签:
【中文标题】QML/QT 如何将对象从 C++ 转换为 QML?【英文标题】:QML/QT How to convert object from C++ to QML? 【发布时间】:2020-09-23 19:32:13 【问题描述】:我花了一些时间,但最终我设法将 javascript/QML POJO 转换为不是从 QObject 派生的自定义对象。
我认为通过一个工作示例更容易理解我的问题。所以让我们从这个开始:
struct SomeType /* Just a plain struct that does not derive from QObject! */ ;
SomeType FooFactory::convertQMLToSomeType(const QJSValue& val)
SomeType result = /*... some kind of conversion takes place here ... */
return result;
void FooFactory::registerTypes(QQmlEngine& engine)
QMetaType::registerConverter<QJSValue, SomeType>(FooFactory::convertQMLToSomeType);
它的作用是注册一个转换器,用于将QSValue
转换为SomeType
。所以现在,每当我在 QML 中做这样的事情时
my_prop = "foo": "some plain javascript object" ;
假设 my_prop
在相应的 C++ 类中是这样暴露的:
Q_PROPERTY(SomeType my_prop MEMBER _myProp);
SomeType _myProp;
// Somewhere else outside the class, this is needed for registering the converter
Q_DECLARE_METATYPE(SomeType);
字符串被隐式转换为SomeType
,无需手动操作。
..
太棒了!
但是转换的相反方向呢?我需要 QML 来处理字符串,而不是 QVariant(SomeType)
对象(在处理元系统时,QT 总是在内部使用 QVariant
包装器来存储用户定义的类型)。
我已经尝试过像这样注册一个逆变器:
QMetaType::registerConverter<SomeType, QJSValue>(FooFactory::convertBackToQML);
或者这个
QMetaType::registerConverter<QVariant(SomeType), QJSValue>(FooFactory::convertBackToQML);
但是这些方法都不起作用。我相信第二行很有希望,但由于注册静态元类型的问题,我什至无法编译那行。
那么,我将如何解决这个问题?简短提醒一下,我无法从 QObject
导出 SomeType
,是的,我知道这是做这类事情的最常见方法。
有人有想法吗?还是我在叫错树?非常感谢!
【问题讨论】:
你的结构可以是 Q_GADGET 而不是 QObject 吗? 很遗憾没有。该结构是从与 QT 没有任何联系的封装库中使用的,因此我无法在其中添加这些声明。 【参考方案1】:这可能不是您想要的,但它也可能是您唯一的选择。您可以围绕您的结构创建一个 QObject 包装类。只需为要公开的结构中的任何值创建属性。
class SomeWrapper : public QObject
Q_OBJECT
Q_PROPERTY(QString someData READ someData WRITE setSomeData NOTIFY someDataChanged)
public:
explicit SomeWrapper(QObject *parent = nullptr) : QObject(parent)
QString someData() return m_struct.someData;
void setSomeData(QString data)
if (data != m_struct.someData)
m_struct.someData = data;
emit someDataChanged();
signals:
void someDataChanged();
private:
SomeType m_struct;
;
【讨论】:
【参考方案2】:如果您想像使用普通 JavaScript 对象一样操作您的结构,那么另一种选择可能是使用 QVariantMap
作为您的属性的类型。然后,您可以在属性的 getter 和 setter 中定义所需的转换:
class Whichever : public QObject
Q_OBJECT
Q_PROPERTY(QVariantMap my_prop READ myProp WRITE setMyProp)
QVariantMap myProp() const
QVariantMap map;
map["some_field"] = _myProp.someField;
// Fill the other fields as needed.
return map;
void setMyProp(const QVariantMap& map)
_myProp.someField = map["some_field"].toString();
// Fill the other _myProp fields as needed.
;
QVariantMap
和实际 JavaScript 对象之间的转换将由 QML 引擎自动处理。通过嵌套相应的QVariantMap
s 也应该可以嵌套 JavaScript 对象。
当然,这个选项使得属性声明对于它对应的类型不是那么明确,如果你需要声明这个类型的多个属性,可能需要更多的样板代码(你可以定义和使用你自己的如果需要,宏)。但这可能是实现您所描述的最简单的方法之一。
【讨论】:
以上是关于QML/QT 如何将对象从 C++ 转换为 QML?的主要内容,如果未能解决你的问题,请参考以下文章
如何从 C++ 代码将 QML 对象转换为 QQuickWindow?
如何在 Blackberry Cascades qml 和 qt 中点击列表项组件