【问题标题】:QML/QT How to convert object from C++ to QML?QML/QT 如何将对象从 C++ 转换为 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&lt;SomeType, QJSValue&gt;(FooFactory::convertBackToQML);

或者这个

QMetaType::registerConverter&lt;QVariant(SomeType), QJSValue&gt;(FooFactory::convertBackToQML);

但是这些方法都不起作用。我相信第二行很有希望,但由于注册静态元类型的问题,我什至无法编译那行。

那么,我将如何解决这个问题?简短提醒一下,我无法从 QObject 导出 SomeType,是的,我知道这是做这类事情的最常见方法。

有人有想法吗?还是我在叫错树?非常感谢!

【问题讨论】:

  • 你的结构可以是 Q_GADGET 而不是 QObject 吗?
  • 很遗憾没有。该结构是从与 QT 没有任何联系的封装库中使用的,因此我无法在其中添加这些声明。

标签: c++ qt qml


【解决方案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 引擎自动处理。通过嵌套相应的QVariantMaps 也应该可以嵌套 JavaScript 对象。

    当然,这个选项使得属性声明对于它对应的类型不是那么明确,如果你需要声明这个类型的多个属性,可能需要更多的样板代码(你可以定义和使用你自己的如果需要,宏)。但这可能是实现您所描述的最简单的方法之一。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2021-03-22
      • 1970-01-01
      • 2019-11-27
      • 1970-01-01
      • 1970-01-01
      • 2018-05-17
      • 2012-12-06
      相关资源
      最近更新 更多