QML其实是对ECMAScript的扩展,融合了Qt object系统,它是一种新的解释性语言,QML引擎虽然由Qt C++实现,但QML对象的运行环境说到底和C++对象的上下文环境是不通的,是平行的两个世界,如果想在QML中访问C++对象,那么必然要找到一种途径在两个运行环境之间建立沟通的桥梁。
Qt提供了两种在QML环境中使用C++对象的方式:
(1)在C++中实现一个类,注册为QML环境的一个类型,在QML环境中使用该类型创建对象
(2)在C++中构造一个对象,将这个对象设置为QML的上下文属性,在QML环境中直接使用该属性
一 类的方式实现在QML中使用C++对象
1. 定义可以导出的C++类
要想将一个类或对象导出到QML中,必须满足以下几个条件:
(1)从QObject或QObject的派生类继承
(2)使用Q_OBJECT宏
(3)Q_INVOKABLE宏
在定义一个类的成员函数时使用Q_INVOKABLE宏来修饰,就可以让该方法被元对象系统调用,这个宏必须放在返回类型前面
(4)Q_ENUMS宏
如果要导出的类定义了想在QML中使用的枚举类型,可以使用Q_ENUM宏将该枚举注册到元对象系统中
(5)Q_PROPERTY宏
Q_PROPERTY宏用来定义可以通过元对象系统访问的属性,通过它定义的属性,可以在QML中访问,修改,也可以在属性变化时发射特定的信号
例子:
#ifndef COLORMAKER_H #define COLORMAKER_H #include <QObject> #include <QColor> class ColorMaker : public QObject { Q_OBJECT Q_ENUMS(GenerateAlgorithm) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QColor timeColor READ timeColor) public: explicit ColorMaker(QObject *parent = nullptr); ~ColorMaker(); enum GenerateAlgorithm { RandomRGB, RandomRed, RandomGreen, RandomBlue, LinearIcrease }; QColor color() const {return m_currentColor;} void setColor(const QColor& color); QColor timeColor() const; Q_INVOKABLE GenerateAlgorithm alorithm() const; Q_INVOKABLE void serAlgorithm(GenerateAlgorithm algorithm); signals: void colorChanged(const QColor& color); void currentTime(const QString& strTime); public slots: void start(); void stop(); protected: void timerEvent(QTimerEvent *e); private: GenerateAlgorithm m_algorithm; QColor m_currentColor; int m_nColorTimer; }; #endif // COLORMAKER_H
#include "colormaker.h" #include <QTime> #include <QTimerEvent> #include <QDebug> ColorMaker::ColorMaker(QObject *parent) : QObject(parent) ,m_algorithm(RandomRGB) ,m_currentColor(Qt::black) ,m_nColorTimer(0) { qsrand(QDateTime::currentDateTime().toTime_t()); } ColorMaker::~ColorMaker() { } void ColorMaker::setColor(const QColor &color) { m_currentColor = color; emit colorChanged(color); } QColor ColorMaker::timeColor() const { QTime time = QTime::currentTime(); qDebug() << time.toString("yyyy-MM-dd hh:mm:ss"); int r = time.hour(); int g = time.minute() * 2; int b = time.second() * 4; qDebug() << r << ":"<< g << ":"<< b; return QColor(r,g,b); } ColorMaker::GenerateAlgorithm ColorMaker::alorithm() const { return m_algorithm; } void ColorMaker::serAlgorithm(ColorMaker::GenerateAlgorithm algorithm) { m_algorithm = algorithm; } void ColorMaker::start() { qDebug() << "ColorMaker start"; if (m_nColorTimer == 0) { m_nColorTimer = startTimer(1000); } } void ColorMaker::stop() { if (m_nColorTimer > 0) { killTimer(m_nColorTimer); m_nColorTimer = 0; } } void ColorMaker::timerEvent(QTimerEvent *e) { if (e->timerId() == m_nColorTimer) { switch (m_algorithm) { case RandomRGB: m_currentColor.setRgb(qrand()%255, qrand()%255,qrand()%255); break; case RandomRed: m_currentColor.setRed(qrand()%255); break; case RandomGreen: m_currentColor.setGreen(qrand()%255); break; case RandomBlue: m_currentColor.setBlue(qrand()%255); break; case LinearIcrease: { int r = m_currentColor.red() + 10; int g = m_currentColor.green() + 10; int b = m_currentColor.blue() + 10; m_currentColor.setRgb(r%255,g%255,b%255); } break; default: break; } emit colorChanged(m_currentColor); emit currentTime(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss")); } else { return QObject::timerEvent(e); } }
2. 注册QML类型
要注册一个QML类型,有多种方法:
qmlRegisterSingletonType()注册一个单例类型
qmlRegisterType()注册一个非单例类型
qmlRegisterTypeNotAvaliable()注册一个类型用来占位
qmlRegisterUncreatableType()通常用来注册一个具有附加属性的附加类型,具体参考Qt SDK
template<typename T> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName); template<typename T, int metaObjectRevision> int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
uri 指定唯一的包名
qmlname 是QML中可以使用的类名
qmlRegisterType<ColorMaker>("an.qt.ColorMaker", 1, 0, "ColorMaker");
3. 在QML中导入类型
一旦你在C++中注册好了QML类型,就可以在QML文档中引入你注册的包,然后使用注册的类型了
import an.qt.ColorMaker 1.0
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QQuickView> #include <QtQml> #include "colormaker.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); //QQmlApplicationEngine engine; //engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); //if (engine.rootObjects().isEmpty()) // return -1; qmlRegisterType<ColorMaker>("an.qt.ColorMaker", 1, 0, "ColorMaker"); QQuickView viewer; viewer.setResizeMode(QQuickView::SizeRootObjectToView); viewer.setSource(QUrl("qrc:///main.qml")); viewer.show(); return app.exec(); }
4. 在QML中创建由C++导出的类型的实例并使用
引入包后,你可以在QML中创建 C++导入类型的对象了,与QML内建类型的使用完全一样。
Rectangle { 360; height: 360; ColorMaker { id:colorMaker; color:Qt.green; } }
例:
import QtQuick 2.2 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.3 import QtQml 2.11 import an.qt.ColorMaker 1.0 Rectangle { 360; height: 360; Text { id: timeLabel; anchors.left: parent.left; anchors.leftMargin: 4; anchors.top : parent.top; anchors.topMargin: 4; font.pixelSize: 26; } ColorMaker { id:colorMaker; color:Qt.green; } Rectangle { id:colorRect; anchors.centerIn: parent; 200; height: 200; color: "blue"; } Button { id:start; text:"start"; anchors.left: parent.left; anchors.leftMargin: 4; anchors.bottom: parent.bottom; anchors.bottomMargin: 4; onClicked: { console.log("start onClicked"); colorMaker.start(); } } Button { id:stop; text:"stop"; anchors.left: start.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; anchors.bottomMargin: 4; onClicked: { colorMaker.stop(); } } function changeAlgorithm(button, algorithm) { switch(algorithm) { case 0: button.text = "RandomRGB" break; case 1: button.text ="RandomRed"; break; case 2: button.text ="RandomGreen"; break; case 3: button.text ="RandomBlue"; break; case 4: button.text ="LinearIncrease"; break; } } Button { id:colorAlgorithm; text:"RandomRGB"; anchors.left:stop.right; anchors.leftMargin: 4; anchors.bottom: stop.bottom; onClicked: { var algorithm = (colorMaker.alorithm() + 1 ) % 5; changeAlgorithm(colorAlgorithm,algorithm); colorMaker.serAlgorithm(algorithm); } } Button { id:quit text:"quit" anchors.left: colorAlgorithm.right; anchors.leftMargin: 4; anchors.bottom: colorAlgorithm.bottom; onClicked: { Qt.quit(); } } Component.onCompleted: { colorMaker.color = Qt.rgba(0,180,120,255); colorMaker.serAlgorithm(colorMaker.LinearIcrease); changeAlgorithm(colorAlgorithm,colorMaker.alorithm()); } Connections { target: colorMaker; onCurrentTime: { timeLabel.text = strTime; console.log("onCurrentTime"); // timeLabel.color = colorMaker.timeColor; } } Connections { target: colorMaker; onColorChanged: { colorRect.color = color; } } } /*Rectangle { 600 height: 600 Image { id: imageLabel; 600; height: 540; anchors.top: parent.top anchors.left: parent.left fillMode: Image.PreserveAspectFit source: "http://images.cnblogs.com/cnblogs_com/xiaobingqianrui/1185116/o_Image%201.png" } Button { id:openBtn 100; height: 40; text: "Open"; anchors.top:imageLabel.bottom anchors.topMargin: 10; anchors.left: parent.left anchors.leftMargin: 10; onClicked:fileDialog.open(); } Label { id:pathLabel; text: "Hello world" font.pixelSize: 22 font.italic: true color: "steelblue" anchors.top:imageLabel.bottom anchors.topMargin: 10; anchors.left: openBtn.right anchors.leftMargin: 10 } FileDialog { id:fileDialog title: "please choose a file" nameFilters: ["Image Files (*.jpg *.png *.gif)"] onAccepted: { imageLabel.source=fileDialog.fileUrl; console.log(fileDialog.fileUrl); var imageFile = new String(fileDialog.fileUrl); pathLabel.text=imageFile.slice(8); } } }*/
二 对象的方式实现在QML中使用C++对象
1. 注册属性
viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker);
2. 在QML中使用关联到的C++对象的属性
一旦调用setContextProperty()导出了属性,就可以在QML中使用了,不需要import语句
import QtQuick 2.2 import QtQuick.Window 2.2 import QtQuick.Controls 1.4 import QtQuick.Controls.Styles 1.4 import QtQuick.Dialogs 1.3 import QtQml 2.11 //import an.qt.ColorMaker 1.0 Rectangle { 360; height: 360; Text { id: timeLabel; anchors.left: parent.left; anchors.leftMargin: 4; anchors.top : parent.top; anchors.topMargin: 4; font.pixelSize: 26; } /* ColorMaker { id:colorMaker; color:Qt.green; }*/ Rectangle { id:colorRect; anchors.centerIn: parent; 200; height: 200; color: "blue"; } Button { id:start; text:"start"; anchors.left: parent.left; anchors.leftMargin: 4; anchors.bottom: parent.bottom; anchors.bottomMargin: 4; onClicked: { console.log("start onClicked"); colorMaker.start(); } } Button { id:stop; text:"stop"; anchors.left: start.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; anchors.bottomMargin: 4; onClicked: { colorMaker.stop(); } } function changeAlgorithm(button, algorithm) { switch(algorithm) { case 0: button.text = "RandomRGB" break; case 1: button.text ="RandomRed"; break; case 2: button.text ="RandomGreen"; break; case 3: button.text ="RandomBlue"; break; case 4: button.text ="LinearIncrease"; break; } } Button { id:colorAlgorithm; text:"RandomRGB"; anchors.left:stop.right; anchors.leftMargin: 4; anchors.bottom: stop.bottom; onClicked: { var algorithm = (colorMaker.alorithm() + 1 ) % 5; changeAlgorithm(colorAlgorithm,algorithm); colorMaker.serAlgorithm(algorithm); } } Button { id:quit text:"quit" anchors.left: colorAlgorithm.right; anchors.leftMargin: 4; anchors.bottom: colorAlgorithm.bottom; onClicked: { Qt.quit(); } } Component.onCompleted: { colorMaker.color = Qt.rgba(0,180,120,255); //colorMaker.serAlgorithm(colorMaker.LinearIcrease); colorMaker.serAlgorithm(2); changeAlgorithm(colorAlgorithm,colorMaker.alorithm()); } Connections { target: colorMaker; onCurrentTime: { timeLabel.text = strTime; console.log("onCurrentTime"); // timeLabel.color = colorMaker.timeColor; } } Connections { target: colorMaker; onColorChanged: { colorRect.color = color; } } }