[Qt5] How to connect c++ with QML


Qt5處於過度階段,架構繁瑣,學習成本不低。尤其是UI代碼竟然被重寫,變了天。

Qt中的c++可能是連接OPENCV與QML的一個不錯的橋梁,在此學習這部分實用的技術。

Reference: http://blog.csdn.net/foruok/article/details/32698603

一、在 QML 中調用 c++

  

  1. 實現 c++

  2. 注冊 QML 類型

  3. QML 中導入類型

  4. QML 創建由 C++ 導出的類型的實例並使用

 

Qt 提供了兩種在 QML 環境中使用 C++ 對象的方式:

  1. 在 C++ 中實現一個,注冊到 QML 環境中, QML 環境中使用該類型創建對象
  2. 在 C++ 中構造一個對象,將這個對象設置為 QML 的上下文屬性,在 QML 環境中直接使用改屬性

對要導出的 C++ 類都有要求,不是一個類的所有方法、變量都可以被 QML 使用。

因此我們先來看看怎樣讓一個方法屬性可以被 QML 使用。

 


  

對要導出的 C++ 類都有要求,不是一個類的所有方法、變量都可以被 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 / WRITE / NOTIFY 三個選項。我們來看看都是什么含義。
  • 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); ... };

 


  1. 實現 c++類 (define好了類,之后實現各函數)

  2. 注冊 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;
        }
    }
}
qml中調用c++

 


 

  1. 實現 c++

  2. 注冊 QML 類型

  3. 在 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 對象

 
我們可以使用 QML 對象的信號、槽,訪問它們的屬性,都沒有問題,因為很多 QML 對象對應的類型,原本就是 C++ 類型,比如
    • Image 對應 QQuickImage ,
    • Text 對應 QQuickText
但是,這些與 QML 類型對應的 C++ 類型都是私有的,你寫的 C++ 代碼也不能直接訪問。怎么辦?
 
Qt 最核心的一個基礎特性,就是 元對象系統。
通過元對象系統,你可以 查詢 QObject 的某個派生類的類名、有哪些信號、槽、屬性、可調用方法等等信息
然后也可以使用 QMetaObject::invokeMethod() 調用 QObject 的某個注冊到元對象系統中的方法。
而對於使用 Q_PROPERTY 定義的屬性,可以使用 QObject 的 property() 方法訪問屬性,如果該屬性定義了 WRITE 方法,還可以使用 setProperty() 修改屬性。
 
所以只要我們找到 QML 環境中的某個對象,就可以通過元對象系統來訪問它的屬性、信號、槽等。
關鍵就是:查找對象!
 
查找如下QML的對象:
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"; } }

 

我們給根元素起了個名字 "rootRect" ,給退出按鈕起了個名字 "quitButton" ,給文本起了名字 "textLabel" 。
我們會在 C++ 代碼中通過這些個名字來查找對應的對象並改變它們。
 
#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
ChangeQmlColor定義
#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);
}
ChangeQmlColor實現

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM