Qt5處於過度階段,架構繁瑣,學習成本不低。尤其是UI代碼竟然被重寫,變了天。
Qt中的c++可能是連接OPENCV與QML的一個不錯的橋梁,在此學習這部分實用的技術。
Reference: http://blog.csdn.net/foruok/article/details/32698603
一、在 QML 中調用 c++
-
實現 c++類
-
注冊 QML 類型
-
在 QML 中導入類型
-
在 QML 創建由 C++ 導出的類型的實例並使用
Qt 提供了兩種在 QML 環境中使用 C++ 對象的方式:
- 在 C++ 中實現一個類,注冊到 QML 環境中, QML 環境中使用該類型創建對象
- 在 C++ 中構造一個對象,將這個對象設置為 QML 的上下文屬性,在 QML 環境中直接使用改屬性
對要導出的 C++ 類都有要求,不是一個類的所有方法、變量都可以被 QML 使用。
因此我們先來看看怎樣讓一個方法或屬性可以被 QML 使用。
- 從 QObject 或 QObject 的派生類繼承
- 使用 Q_OBJECT 宏
信號,槽 可以直接被調用 (方法)
成員函數時使用 Q_INVOKABLE 宏來修飾,可以讓該方法被元對象系統調用。
class ColorMaker : public QObject { Q_OBJECT public: ColorMaker(QObject *parent = 0); ~ColorMaker(); Q_INVOKABLE GenerateAlgorithm algorithm() const; Q_INVOKABLEvoid setAlgorithm(GenerateAlgorithm algorithm); signals: void colorChanged(const QColor & color); void currentTime(const QString &strTime); publicslots: void start(); void stop(); };
QML 中使用 ${Object}.${method} 來訪問:
Component.onCompleted: {
colorMaker.color = Qt.rgba(0,180,120, 255); colorMaker.setAlgorithm(ColorMaker.LinearIncrease); changeAlgorithm(colorAlgorithm, colorMaker.algorithm()); }
Q_PROPERTY 宏 (屬性)
Q_PROPERTY 宏用來定義可通過元對象系統訪問的屬性。
通過它定義的屬性,可以在 QML 中訪問、修改,也可以在屬性變化時發射特定的信號。
要想使用 Q_PROPERTY 宏,你的類必須是 QObject 的后裔,必須在類首使用 Q_OBJECT 宏。
- READ 標記 如果你沒有為屬性指定 MEMBER 標記,則 READ 標記必不可少;聲明一個讀取屬性的函數,該函數一般沒有參數,返回定義的屬性。
- WRITE 標記 可選配置。聲明一個設定屬性的函數。它指定的函數,只能有一個與屬性類型匹配的參數,必須返回 void 。
- NOTIFY 標記 可選配置。給屬性關聯一個信號(該信號必須是已經在類中聲明過的),當屬性的值發生變化時就會觸發該信號。信號的參數,一般就是你定義的屬性。
class QQuickText : public QQuickImplicitSizeItem { Q_OBJECT Q_ENUMS(HAlignment) Q_PROPERTY(QString text READ text WRITE setText NOTIFY textChanged) Q_PROPERTY(QFont font READ font WRITE setFont NOTIFY fontChanged) Q_PROPERTY(QColor color READ color WRITE setColor NOTIFY colorChanged) ... public: enum HAlignment { AlignLeft = Qt::AlignLeft, AlignRight = Qt::AlignRight, AlignHCenter = Qt::AlignHCenter, AlignJustify = Qt::AlignJustify }; ... QString text() const; void setText(const QString &); QFont font() const; void setFont(const QFont &font); QColor color() const; void setColor(const QColor &c); ... };
-
實現 c++類 (define好了類,之后實現各函數)
-
注冊 QML 類型 (下一步)
要注冊一個 QML 類型,有多種方法可用,如
qmlRegisterSingletonType() 用來注冊一個單例類型,
qmlRegisterType() 注冊一個非單例的類型, // 模板函數
qmlRegisterTypeNotAvailable() 注冊一個類型用來占位,
qmlRegisterUncreatableType() 通常用來注冊一個具有附加屬性的附加類
其中一個原型:
template<typename T>
// 包名,主版本,次版本,類名
int qmlRegisterType(const char *uri, int versionMajor, int versionMinor, const char *qmlName);
#include <QtGui/QGuiApplication> #include "qtquick2applicationviewer.h" #include <QtQml> #include "colorMaker.h"
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv);
// 注冊qml類型 qmlRegisterType<ColorMaker>("an.qt.ColorMaker", 1, 0, "ColorMaker"); QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml")); viewer.showExpanded(); return app.exec(); }

import QtQuick 2.0 import QtQuick.Controls 1.1 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: { colorMaker.start(); } } Button { id: stop; text: "stop"; anchors.left: start.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; 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: start.bottom; onClicked: { var algorithm = (colorMaker.algorithm() + 1) % 5; changeAlgorithm(colorAlgorithm, algorithm); colorMaker.setAlgorithm(algorithm); } } Button { id: quit; text: "quit"; anchors.left: colorAlgorithm.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; onClicked: { Qt.quit(); } } Component.onCompleted: { colorMaker.color = Qt.rgba(0,180,120, 255); colorMaker.setAlgorithm(ColorMaker.LinearIncrease); changeAlgorithm(colorAlgorithm, colorMaker.algorithm()); } Connections { target: colorMaker; onCurrentTime:{ timeLabel.text = strTime; timeLabel.color = colorMaker.timeColor; } } Connections { target: colorMaker; onColorChanged:{ colorRect.color = color; } } }
-
實現 c++類
-
注冊 QML 類型
-
在 QML 中導入類型 ( 下一步 )
將 對象 直接作為參數 傳入 QML
把 C++ 中創建的對象作為屬性傳遞到 QML 環境中,然后在 QML 環境中訪問。就不需要 import 語句了!
將一個對象注冊為屬性:
#include <QtGui/QGuiApplication> #include "qtquick2applicationviewer.h" #include <QtQml> #include "colorMaker.h" int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QtQuick2ApplicationViewer viewer;
// viewer.rootContext() 返回的是 QQmlContext 對象。
// QQmlContext 類代表一個 QML 上下文,它的 setContextProperty() 方法可以為該上下文設置一個全局可見的屬性。 viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker); // 從堆上分配了一個 ColorMaker 對象 viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml")); viewer.showExpanded(); return app.exec(); }
貌似,這個方法比較方便吶。

import QtQuick 2.0 import QtQuick.Controls 1.1 //[1] //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; } /* [2] 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: { colorMaker.start(); } } Button { id: stop; text: "stop"; anchors.left: start.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; 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: start.bottom; onClicked: { var algorithm = (colorMaker.algorithm() + 1) % 5; changeAlgorithm(colorAlgorithm, algorithm); colorMaker.setAlgorithm(algorithm); } } Button { id: quit; text: "quit"; anchors.left: colorAlgorithm.right; anchors.leftMargin: 4; anchors.bottom: start.bottom; onClicked: { Qt.quit(); } } Component.onCompleted: { colorMaker.color = Qt.rgba(0,180,120, 255); //[3] //colorMaker.setAlgorithm(ColorMaker.LinearIncrease); colorMaker.setAlgorithm(2); changeAlgorithm(colorAlgorithm, colorMaker.algorithm()); } Connections { target: colorMaker; onCurrentTime:{ timeLabel.text = strTime; timeLabel.color = colorMaker.timeColor; } } Connections { target: colorMaker; onColorChanged:{ colorRect.color = color; } } }
二、在c++中使用 QML 對象
-
- Image 對應 QQuickImage ,
- Text 對應 QQuickText
import QtQuick 2.0 import QtQuick.Controls 1.1 Rectangle { objectName: "rootRect"; width: 360; height: 360; Text { objectName: "textLabel"; text: "Hello World"; anchors.centerIn: parent; font.pixelSize: 26; } Button { anchors.right: parent.right; anchors.rightMargin: 4; anchors.bottom: parent.bottom; anchors.bottomMargin: 4; text: "quit"; objectName: "quitButton"; } }
#include <QtGui/QGuiApplication> #include "qtquick2applicationviewer.h" #include <QQuickItem> #include "changeColor.h" #include <QMetaObject> #include <QDebug> #include <QColor> #include <QVariant>
int main(int argc, char *argv[]) { QGuiApplication app(argc, argv); QtQuick2ApplicationViewer viewer; viewer.setMainQmlFile(QStringLiteral("qml/callQml/main.qml")); viewer.showExpanded(); QQuickItem * rootItem = viewer.rootObject(); new ChangeQmlColor(rootItem); // 內部通過一個定時器,一秒改變一次傳入對象的顏色
QObject * quitButton = rootItem->findChild<QObject*>("quitButton"); if(quitButton) {
// clicked() 信號連接到 QGuiApplication 的 quit() 槽上 QObject::connect(quitButton, SIGNAL(clicked()), &app, SLOT(quit())); } QObject *textLabel = rootItem->findChild<QObject*>("textLabel"); if(textLabel) { //1. failed call
bool bRet = QMetaObject::invokeMethod(textLabel, "setText", Q_ARG(QString, "world hello")); qDebug() << "call setText return - " << bRet; textLabel->setProperty("color", QColor::fromRgb(255,0,0));
//2. good call bRet = QMetaObject::invokeMethod(textLabel, "doLayout"); // 對應的c++中的接口 名詞不同,所以上面的失敗了 qDebug() << "call doLayout return - " << bRet; } return app.exec(); }

#ifndef CHANGECOLOR_H #define CHANGECOLOR_H #include <QObject> #include <QTimer> class ChangeQmlColor : public QObject { Q_OBJECT public: ChangeQmlColor(QObject *target, QObject *parent = 0); ~ChangeQmlColor(); protected slots: void onTimeout(); private: QTimer m_timer; QObject *m_target; }; #endif

#include "changeColor.h" #include <QDateTime> #include <QColor> #include <QVariant> ChangeQmlColor::ChangeQmlColor(QObject *target, QObject *parent) : QObject(parent) , m_timer(this) , m_target(target) { qsrand(QDateTime::currentDateTime().toTime_t()); connect(&m_timer, SIGNAL(timeout()), this, SLOT(onTimeout())); m_timer.start(1000); } ChangeQmlColor::~ChangeQmlColor() {} void ChangeQmlColor::onTimeout() { QColor color = QColor::fromRgb(qrand()%256, qrand()%256, qrand()%256); m_target->setProperty("color", color); }