C++类的属性――
(1)修改头文件Gemini.h
#ifndef GEMINI_H #define GEMINI_H // Gemini.h #include#include class Gemini : public QObject { Q_OBJECT Q_ENUMS(BALL_COLOR) Q_PROPERTY(unsigned int ballNumber READ ballNumber WRITE setBallNumber NOTIFY ballNumberChanged) public: Gemini() : m_ballColor(BALL_COLOR_YELLOW), m_ballNumber(0) { qDebug() << "Gemini::Gemini() called"; } enum BALL_COLOR { BALL_COLOR_YELLOW, BALL_COLOR_RED, BALL_COLOR_BLUE, BALL_COLOR_ALL }; unsigned int ballNumber() const { return m_ballNumber; } void setBallNumber(const unsigned int &ballNumber) { if(ballNumber != m_ballNumber) { m_ballNumber = ballNumber; emit ballNumberChanged(); } } Q_INVOKABLE void stop() { qDebug() << "Gemini::stop() called"; } signals: void begin(); void ballNumberChanged(); public slots: void doSomething(BALL_COLOR ballColor) { qDebug() << "Gemini::doSomething() called with" << ballColor; if(ballColor != m_ballColor) { m_ballColor = ballColor; qDebug() << "ball color changed"; } } private: BALL_COLOR m_ballColor; unsigned int m_ballNumber; }; #endif // GEMINI_H
Gemini类中添加了Q_PROPERTY()宏,用来在QObject派生类中声明属性,这个属性如同类的数据成员一样,但它又有一些额外的特性可通过Qt元对象系统来访问。
下面是Q_PROPERTY()宏的原型:
Q_PROPERTY()(type name
(READ getFunction [WRITE setFunction] |
MEMBER memberName [(READ getFunction | WRITE setFunction)])
[RESET resetFunction]
[NOTIFY notifySignal]
[REVISION int]
[DESIGNABLE bool]
[SCRIPTABLE bool]
[STORED bool]
[USER bool]
[CONSTANT]
[FINAL])
属性的type、name是必需的,其它是可选项,常用的有READ、WRITE、NOTIFY。属性的type可以是QVariant支持的任何类型,也可以是自定义类型,包括自定义类、列表类型、组属性等。另外,属性的READ、WRITE、RESET是可以被继承的,也可以是虚函数,这些特性并不常用。
READ:读取属性值,如果没有设置MEMBER的话,它是必需的。一般情况下,函数是个const函数,返回值类型必须是属性本身的类型或这个类型的const引用,没有参数。
WRITE:设置属性值,可选项。函数必须返回void,有且仅有一个参数,参数类型必须是属性本身的类型或这个类型的指针或引用。
NOTIFY:与属性关联的可选信号。这个信号必须在类中声明过,当属性值改变时,就可触发这个信号,可以没有参数,有参数的话只能是一个类型同属性本身类型的参数,用来记录属性改变后的值。
Q_PROPERTY()的详细用法可参考如下网址:
http://doc.qt.io/qt-5/properties.html#qt-s-property-system
(2)修改main.qml
// main.qml
import QtQuick 2.2
import QtQuick.Window 2.1
import Union.Lotto.Gemini 1.0
Window {
visible: true
width: 360; height: 360
title: "Union Lotto Game"
color: "white"
MouseArea {
anchors.fill: parent
onClicked: {
gemini.begin()
gemini.stop()
gemini.ballNumber = 10
}
}
Gemini {
id: gemini
onBegin: doSomething(Gemini.BALL_COLOR_RED)
onBallNumberChanged: console.log("new ball number is", ballNumber) // 10
Component.onCompleted: console.log("default ball number is", ballNumber) // 0
}
}
Gemini类中的ballNumber属性可以在QML中访问、修改,访问时调用了ballNumber()函数,修改时调用了setBallNumber()函数,同时还发送了一个信号来自动更新这个属性值。
4、注册C++类为QML类型
QObject派生类可以注册到Qt元对象系统,使得该类在QML中同其它内建类型一样,可以作为一个数据类型来使用。QML引擎允许注册可实例化的类型,也可以是不可实例化的类型,常见的注册函数有:
qmlRegisterInterface()
qmlRegisterRevision()
qmlRegisterSingletonType()
qmlRegisterType()
qmlRegisterTypeNotAvailable()
qmlRegisterUncreatableType()
这些注册函数各有其用,可根据实际需要选择,使用时需要包含
templateint qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
这个模板函数注册C++类到Qt元对象系统中,uri是需要导入到QML中的库名,versionMajor和versionMinor是其版本数字,qmlName是在QML中可以使用的类型名。例如上面例子main.cpp中的代码:
qmlRegisterType("Union.Lotto.Gemini", 1, 0, "Gemini");
main.cpp中将Gemini类注册为在QML中可以使用的Gemini类型,主版本为1,次版本为0,库的名字是Union.Lotto.Gemini。main.qml中导入了这个库,使用Gemini构造了一个对象,id为gemini,这样就可以借助id来访问C++了。
注册动作必须在QML上下文创建之前,否则无效。
另外:QQuickView为QtQuickUI提供了一个窗口,可以方便地加载QML文件并显示其界面。QApplication派生自QGuiApplication,而QGuiApplication又派生自QCoreApplication,这三个类是常见的管理Qt应用程序的类。QQmlApplicationEngine可以方便地从一个单一的QML文件中加载应用程序,它派生自QQmlEngine,QQmlEngine则提供了加载QML组件的环境,可以与QQmlComponent、QQmlContext等一起使用。
5、QML上下文属性设置
在C++应用程序加载QML对象时,我们可以直接嵌入一些C++数据来给QML使用,这里需要用到QQmlContext::setContextProperty(),即设置QML上下问属性,它可以是一个简单的类型,也可以是任何我们自定义的类对象。
(1)修改main.cpp
// main.cpp #include#include #include #include int main(int argc, char *argv[