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
{
width: 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
{
width: 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;
width: 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
{
width: 600
height: 600
Image {
id: imageLabel;
width: 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
width: 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
{
width: 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;
width: 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;
}
}
}