QT: QML访问c++的对象属性

目的

本文简介QML与C++ QObject 对象的属性(Property)、方法(Method)与信号(Signal)互操作[1],并举例说明。

基于上一篇文章中介绍的QML对象与C++对象绑定后,QML可以更进一步的与C++对象的属性(Attribute)、方法(Method)与信号(Signal)进行互操作。

属性

如下的例子使用 Q_PROPERTY()宏定义 author属性(Property)的类型为(QString),以及auhor属性对应的 set(setAuthor)方法, get(author)方法以及notify信号槽(authorChanged)。

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
public:
    void setAuthor(const QString &a) {
        if (a != m_author) {
            m_author = a;
            emit authorChanged();
        }
    }
    QString author() const {
        return m_author;
    }
signals:
    void authorChanged();
private:
    QString m_author;
};

在QML中分别调用了author属性的get方法与set方法,与JS属性操作相同,非常方便。
在获取msg.author时,QML engine会自动调用C++中Method::author()方法。
在对msg.author赋值时,QML engine会自动调用C++中Method::setAuthor()方法。

// MyItem.qml
import QtQuick 2.0

Text {
    width: 100; height: 100
    text: msg.author    // invokes Message::author() to get this value

    Component.onCompleted: {
        msg.author = "Jonah"  // invokes Message::setAuthor()
    }
}

QML与C++互操作的前提是必须要和C++的QObject 对象建立绑定关系,如下使用setContextProperty()建立MyItem.qml中的msg对象与C++的Message对象的绑定关系后,本例便可正常运行。

int main(int argc, char *argv[]) {
    QGuiApplication app(argc, argv);

    QQuickView view;
    Message msg;
    view.engine()->rootContext()->setContextProperty("msg", &msg);
    view.setSource(QUrl::fromLocalFile("MyItem.qml"));
    view.show();

    return app.exec();
}

数据类型转换

QML与C++对象的属性相互访问时,会引用到QML与C++的自动数据类型转换[2]。举例来说,如QML中js的int类型会自动转换成C++中的int或者unsigned int类型。下图是常用的QML与C++的数据类型转换表:
在这里插入图片描述

List与Map

List与Map类型在QML与C++的数据类型转换中也经常使用。比如QML中ListViewMode就是一个List类型。通常来说,C++中的QVariantList类型会被自动转换成QML JavaScript中的Array类型,而QVariantMap会被自动转换成QML JavaScript中的Object类型,反之亦然。

List与Map在C++与QML中的相互转换是传值的,而非传址。这意味这对C++中QVariantList或QVariantMap中内容的修改,并不会影响QML中的对象内容。因此,如果需要将C++中List或Map的修改传递到QML中,需要将整个List或Map都传递给QML。

其他数据类型

QML与C++之间的数据类型转换还支持一些其他类型,如枚举类型(Enum),QDateTime类型等。更多内容可以参考引用1中的说明。

方法

QML与C++之间可以相互调用彼此的方法。如果是QML调用C++的类成员方法,则此方法需要使用Qt的slot或者使用Q_INVOKABLE修饰。如上文中就分别演示了这两种方法。

如果C++需要调用QML的方法,则需要使用C++ QObject::invokeMethod()方法,如下例中的C++代码主动调用了QML代码中的readValues()方法,c++传递的参数分别是QVariant和QVariantMap,调用到JS代码时会自动转换成JS中的array和object对象。

// C++
QQuickView view(QUrl::fromLocalFile("MyItem.qml"));

QVariantList list;
list << 10 << QColor(Qt::green) << "bottles";

QVariantMap map;
map.insert("language", "QML");
map.insert("released", QDate(2010, 9, 21));

QMetaObject::invokeMethod(view.rootObject(), "readValues",
        Q_ARG(QVariant, QVariant::fromValue(list)),
        Q_ARG(QVariant, QVariant::fromValue(map)));
// QML
Item {
    function readValues(anArray, anObject) {
        for (var i=0; i<anArray.length; i++)
            console.log("Array item:", anArray[i])

        for (var prop in anObject) {
            console.log("Object item:", prop, "=", anObject[prop])
        }
    }
}

信号

QML中可以接收到C++中的信号槽(signal)触发事件。如下面例子中C++定义的 newMessagePosted()事件。

class MessageBoard : public QObject
{
    Q_OBJECT
public:
   // ...
signals:
   void newMessagePosted(const QString &subject);
};

下面的QML中只需要定义onNewMessagePosted,则C++触发了newMessagePosted()事件后,QML中的方法就会被自动调用。前提是需要将MessageBoard通过qmlRegisterType()等方法注册到QML engine中。

MessageBoard {
    onNewMessagePosted: console.log("New message received:", subject)
}

生命周期

C++中的对象销毁了,QML能保证正常工作吗

QML对C++对象的管理遵循如下几个原则:

  1. 谁分配谁管理。如果C++中new的对象,c++自己管理,反之亦然。
  2. QQmlEngine::setObjectOwnership() 与 QQmlEngine::CppOwnership()可以改变对象的Ownership。
  3. 如果C++中的QML有parent, 则QML不会主动销毁此对象。

引用

[1] https://doc.qt.io/qt-5/qtqml-cppintegration-exposecppattributes.html#properties-with-object-list-types
[2] https://doc.qt.io/qt-5/qtqml-cppintegration-data.html

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值