QT之在QML中使用C++類和對象的兩種方式

  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;
        }
    }
}

複製代碼

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章