在 QML 中使用 C++ 類和對象


Qt Quick 技術的引入,使得你能夠快速構建 UI ,具有動畫、各種絢麗效果的 UI 都不在話下。但它不是萬能的,也有很多局限性,原來 Qt 的一些技術,比如低階的網絡編程如 QTcpSocket ,多線程,又如 XML 文檔處理類庫 QXmlStreamReader / QXmlStreamWriter 等等,在 QML 中要么不可用,要么用起來不方便,所以呢,很多時候我們是會基於這樣的原則來混合使用 QML 和 C++: QML 構建界面, C++ 實現非界面的業務邏輯和復雜運算。

那這篇呢,我們就來看看 QML 和 C++ 之間如何交互。

其實話說回來, QML 的很多基本類型原本就是在 C++ 中實現的,比如 Item 對應 QQuickItem , Image 對應 QQuickImage , Text 對應 QQuickText。這樣看來,在 QML 中訪問 C++ 對象必然不成問題。然也!反過來,在 C++ 中其實也可以使用 QML 對象。對於這兩種情景,我們分別講述。先看如何在 QML 中使用 C++ 類和對象。

我們知道, QML 其實是對 JavaScript 的擴展,融合了 Qt Object 系統,它是一種新的解釋型的語言, QML 引擎雖然由 Qt C++ 實現,但 QML 對象的運行環境,說到底和 C++ 對象的上下文環境是不同的,是平行的兩個世界。如果你想在 QML 中訪問 C++ 對象,那么必然要找到一種途徑來在兩個運行環境之間建立溝通橋梁。

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

(1)在 C++ 中實現一個類,注冊到 QML 環境中, QML 環境中使用該類型創建對象。

(2)在 C++ 中構造一個對象,將這個對象設置為 QML 的上下文屬性,在 QML 環境中直接使用改屬性。


首先我們需要創建一個 Qt Quick App ,新建兩個文件, colorMaker.h 和 colorMaker.cpp 。colorMaker 只是一個示例項目,我在 C++ 中實現一個 ColorMaker 類,它可以被注冊為一個 QML 類型供 QML 像內建類型一樣使用,它的實例也可以導出為 QML 上下文屬性在 QML 中訪問。我們的示例只是在界面頂部顯示當前時間(時間文字的顏色隨時間變化而變化),在界面中間顯示一個變色矩形,在界面底部放置幾個按鈕來控制顏色如何變化。后續會逐步實現這個 colorMaker 工程,這里先看下效果圖:


一、實現可以導出的 C++ 類

我們先介紹前一種方法,大概需要分四步:

(1)實現 C++ 類

(2)注冊 QML 類型

(3)在 QML 中導入類型

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

下面就分別說明這 4 個步驟。


1.1 實現 C++ 類

前提條件

要想將一個類或對象導出到 QML 中,下列前提條件必須滿足:

  • 從 QObject 或 QObject 的派生類繼承。
  • 使用 Q_OBJECT 宏。

看起來好像和使用信號與槽的前提條件一樣……沒錯,的確是一樣的。這兩個條件是為了讓一個類能夠進入 Qt 強大的元對象系統(meta-object system)中,只有使用元對象系統,一個類的某些方法或屬性才可能通過字符串形式的名字來調用,才具有了在 QML 中訪問的基礎條件。

一旦你導出了一個類,在 QML 中就必然要訪問該類的實例的屬性或方法來達到某種目的……而具有什么特征的屬性或方法才可以被 QML 訪問呢?


(1)信號,槽

只要是信號或者槽,都可以在 QML 中訪問,你可以把 C++ 對象的信號連接到 QML 中定義的方法上,也可以把 QML 對象的信號連接到 C++ 對象的槽上,還可以直接調用 C++ 對象的槽或信號。所以,這是最簡單好用的一種途徑。

下面初始 ColorMaker 類的聲明:

class ColorMaker : public QObject
{
    Q_OBJECT
 
public:
    ColorMaker(QObject *parent = 0);
    ~ColorMaker();
    
signals:
    void colorChanged(const QColor & color);
    void currentTime(const QString &strTime);
 
public slots:
    void start();
    void stop();
    
};

我們定義了 start() 和 stop() 兩個槽, colorChanged() 和 currentTime() 兩個信號,都可以在 QML 中使用。


(2)Q_INVOKABLE 宏

在定義一個類的成員函數時使用 Q_INVOKABLE 宏來修飾,就可以讓該方法被元對象系統調用。這個宏必須放在返回類型前面。

我給 ColorMaker 添加了兩個使用 Q_INVOKABLE 宏修飾的方法,現在 ColorMaker 類的聲明變成了這個樣子:

class ColorMaker : public QObject
{
    Q_OBJECT
 
public:
    ColorMaker(QObject *parent = 0);
    ~ColorMaker();
    
    Q_INVOKABLE GenerateAlgorithm algorithm() const;
    Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
 
signals:
    void colorChanged(const QColor & color);
    void currentTime(const QString &strTime);
 
public slots:
    void start();
    void stop();
};

一旦你使用 Q_INVOKABLE 將某個方法注冊到元對象系統中,在 QML 中就可以用${Object}.${method} 來訪問,colorMaker 的 main.qml 中有使用 algorithm() 和 setAlgorithm() 的 QML 代碼 :

Component.onCompleted: {
    colorMaker.color = Qt.rgba(0,180,120, 255);
    colorMaker.setAlgorithm(ColorMaker.LinearIncrease);
    changeAlgorithm(colorAlgorithm, colorMaker.algorithm());
}

我在根元素創建完成時初始化 colorMaker 對象,給它設定了顏色生成算法,同時改變界面上切換顏色生成算法的按鈕的文字。


(3)Q_ENUMS

如果你要導出的類定義了想在 QML 中使用枚舉類型,可以使用 Q_ENUMS 宏將該枚舉注冊到元對象系統中。

ColorMaker 類定義了 GenerateAlgorithm 枚舉類型,支持 RandomRGB / RandomRed 等顏色生成算法。現在 ColorMaker 類的聲明變成了這個樣子:

class ColorMaker : public QObject
{
    Q_OBJECT
    Q_ENUMS(GenerateAlgorithm)
 
public:
    ColorMaker(QObject *parent = 0);
    ~ColorMaker();
    
    enum GenerateAlgorithm{
        RandomRGB,
        RandomRed,
        RandomGreen,
        RandomBlue,
        LinearIncrease
    };
    
    Q_INVOKABLE GenerateAlgorithm algorithm() const;
    Q_INVOKABLE void setAlgorithm(GenerateAlgorithm algorithm);
 
signals:
    void colorChanged(const QColor & color);
    void currentTime(const QString &strTime);
 
public slots:
    void start();
    void stop();
};

一旦你使用 Q_ENUMS 宏注冊了你的枚舉類型,在 QML 中就可以用${CLASS_NAME}.${ENUM_VALUE} 的形式來訪問,比如 ColorMaker.LinearIncrease。


(4)Q_PROPERTY

Q_PROPERTY 宏用來定義可通過元對象系統訪問的屬性,通過它定義的屬性,可以在 QML 中訪問、修改,也可以在屬性變化時發射特定的信號。要想使用 Q_PROPERTY 宏,你的類必須是 QObject 的后裔,必須在類首使用 Q_OBJECT 宏。

下面是 Q_PROPERTY 宏的原型:

Q_PROPERTY(type name
           (READ getFunction [WRITE setFunction] |
            MEMBER memberName [(READ getFunction | WRITE setFunction)])
           [RESET resetFunction]
           [NOTIFY notifySignal]
           [REVISION int]
           [DESIGNABLE bool]
           [SCRIPTABLE bool]
           [STORED bool]
           [USER bool]
           [CONSTANT]
           [FINAL])

是不是很復雜?你可以為一個屬性命名,可以設定的選項數超過10個……我是覺得有點兒頭疼。不過,不是所有的選項都必須設定,看一個最簡短的屬性聲明:

Q_PROPERTY(int x READ x)

上面的聲明定義了一個類型為 int 名為 x 的屬性,通過方法 x() 來訪問。

type name 這兩個字段想必不用細說了吧?type 是屬性的類型,可以是 int / float / QString / QObject / QColor / QFont 等等, name 就是屬性的名字。


其實我們在實際使用中,很少能夠用全 Q_PROPERTY 的所有選項,就往 QML 導出類這種場景來說,比較常用的是 READ / WRITE / NOTIFY 三個選項。我們來看看都是什么含義。

  • READ 標記,如果你沒有為屬性指定 MEMBER 標記,則 READ 標記必不可少。聲明一個讀取屬性的函數,該函數一般沒有參數,返回定義的屬性。
  • WRITE 標記,可選配置。聲明一個設定屬性的函數。它指定的函數,只能有一個與屬性類型匹配的參數,必須返回 void 。
  • NOTIFY 標記,可選配置。給屬性關聯一個信號(該信號必須是已經在類中聲明過的),當屬性的值發生變化時就會觸發該信號。信號的參數,一般就是你定義的屬性。

QML 中的 Text 類型對應 C++ 中的 QQuickText 類,下面是我摘取的部分代碼,可以看到 Q_ENUMS 和 Q_PROPERTY 的使用:

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

(5)完整的 C++ 代碼

現在給我們的 ColorMaker 類添加一些屬性,以便 QML 可以獲取、設置顏色值。新的 ColorMaker.h 如下:

#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:
    ColorMaker(QObject *parent = 0);
    ~ColorMaker();

    enum GenerateAlgorithm{
        RandomRGB,
        RandomRed,
        RandomGreen,
        RandomBlue,
        LinearIncrease
    };

    QColor color() const;
    void setColor(const QColor & color);
    QColor timeColor() const;

    Q_INVOKABLE GenerateAlgorithm algorithm() const;
    Q_INVOKABLE void setAlgorithm(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

現在我們的 ColorMaker 已經是一個完整的類了,有信號、有槽、有使用 Q_INVOKABLE 注冊的方法,還導出了枚舉類型,小小麻雀五臟俱全。 是時候看看它的實現代碼了:

#include "colorMaker.h"
#include <QTimerEvent>
#include <QDateTime>

ColorMaker::ColorMaker(QObject *parent)
    : QObject(parent)
    , m_algorithm(RandomRGB)
    , m_currentColor(Qt::black)
    , m_nColorTimer(0)
{
    qsrand(QDateTime::currentDateTime().toTime_t());
}

ColorMaker::~ColorMaker()
{
}

QColor ColorMaker::color() const
{
    return m_currentColor;
}

void ColorMaker::setColor(const QColor &color)
{
    m_currentColor = color;
    emit colorChanged(m_currentColor);
}

QColor ColorMaker::timeColor() const
{
    QTime time = QTime::currentTime();
    int r = time.hour();
    int g = time.minute()*2;
    int b = time.second()*4;
    return QColor::fromRgb(r, g, b);
}

ColorMaker::GenerateAlgorithm ColorMaker::algorithm() const
{
    return m_algorithm;
}

void ColorMaker::setAlgorithm(GenerateAlgorithm algorithm)
{
    m_algorithm = algorithm;
}

void 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 LinearIncrease:
            {
                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;
        }
        emit colorChanged(m_currentColor);
        emit currentTime(QDateTime::currentDateTime().toString("yyyy-MM-dd hh:mm:ss"));
    }
    else
    {
        QObject::timerEvent(e);
    }
}

我使用一個周期為 1000 的定時器來產生顏色,定時器觸發時根據算法來構造新的顏色值,發射 colorChanged 信號,同時也發送一個 currentTime 信號。


1.2 注冊一個 QML 中可用的類型

ColorMaker 已經就緒了,現在看看怎樣將其注冊為 QML 可以使用的類型。


要注冊一個 QML 類型,有多種方法可用,如qmlRegisterSingletonType()用來注冊一個單例類型, qmlRegisterType()注冊一個非單例的類型,qmlRegisterTypeNotAvailable()注冊一個類型用來占位,qmlRegisterUncreatableType()通常用來注冊一個具有附加屬性的附加類型,……好吧,我這里只說常規的類型注冊,其它的,請您參考 Qt SDK 吧。

qmlRegisterType() 是個模板函數,有兩個原型:

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

前一個原型一般用來注冊一個新類型,而后一個可以為特定的版本注冊類型。后面這個牽涉到 Qt Quick 的類型和版本機制,三言兩語不能盡述,咱們單說前一個原型的使用。要使用 qmlRegisterType 需要包含 QtQml 頭文件。

先說模板參數 typename ,它就是你實現的 C++ 類的類名。qmlRegisterType()的第一個參數 uri ,讓你指定一個唯一的包名,類似 Java 中的那種,一是用來避免名字沖突,而是可以把多個相關類聚合到一個包中方便引用。 qmlName 則是 QML 中可以使用的類名。

下面是 colorMaker 示例的 main.cpp 文件:

#include <QtGui/QGuiApplication>
#include <QtQuick/QQuickView>
#include <QtQml>
#include "colorMaker.h"

int main(int argc, char *argv[])
{
    QGuiApplication app(argc, argv);
    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();
}

上面的代碼將 ColorMaker 類注冊為 QML 類 ColorMaker ,主版本為 1 ,次版本為 0 ,而我起的包名則是 an.qt.ColorMaker。注冊動作一定要放在 QML 上下文創建之前,否則的話,會無效。


1.3 在 QML 中導入 C++ 注冊的類型

一旦你在 C++ 中注冊好了 QML 類型,就可以在 QML 文檔中引入你注冊的包,然后使用注冊的類型。要引入包,使用 import 語句。比如要使用我們注冊的 ColorMaker 類,可以在 QML 文檔中加入下面的 import 語句:

import an.qt.ColorMaker 1.0

1.4 在 QML 中創建 C++ 導入類型的實例

引入包后,你就可以在 QML 中創建 C++ 導入類型的對象了,與 QML 內建類型的使用完全一樣。如下是創建一個 ColorMaker 實例的代碼:

Rectangle {
    width: 360;
    height: 360;
    
    ColorMaker {
        id: colorMaker;
        color: Qt.green;
    }
}

如你所見,ColorMaker 的使用與 Retangle 沒什么區別。如果你想在別處引用 ColorMaker 的實例,可以給實例指定一個唯一的 id ,就像上面的代碼中那樣。


1.5 完整的 colorMaker 實例

如何定義一個可以導出到 QML 中的 C++ 類、如何注冊 QML 類型、如何在 QML 中使用 C++ 導出的類型,都介紹完了,C++ 代碼前面也展示過了,這里看下完整的 main.qml 文檔:

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

執行后的效果圖如下所示:


注:完整項目代碼:Github


main.qml 的界面分成了三部分,頂部是一個 Text ,用來顯示由 ColorMaker 提供的時間,我使用 Connections 對象,指定 target 為 colorMaker ,在 onCurrentTime 信號處理器中改變 timeLabel 的文本和顏色。

我構造了 ColorMaker 類的一個實例, id 為 colorMaker ,初始化顏色值為 green 。colorMaker 實例界面的中間是一個 Rectangle 對象,id 是 colorRect 。我使用 Connections 對象,指定 target 為 colorMaker ,在 onColorChanged 信號處理器中改變 colorRect 的顏色。

界面的底部就是幾個按鈕,使用錨布局把它們排成一行。 start 按鈕的 onClicked 信號處理器調用 colorMaker 的 start() 槽,啟動顏色生成器。 stop 按鈕的 onClicked 信號處理器調用 colorMaker 的 stop() 槽,停止顏色生成器。而 colorAlgorithm 按鈕則每點擊一次就切換一個顏色生成算法,同時調用 changeAlgorithm() 函數,根據算法改變按鈕上的文字。 quit 按鈕一點就退出應用。

好啦,現在再來看看怎樣導出一個對象到 QML 中。


二、導出一個 C++ 對象為 QML 的屬性

上面看了怎樣導出一個 QML 類型在 QML 文檔中使用,你還可以把 C++ 中創建的對象作為屬性傳遞到 QML 環境中,然后在 QML 環境中訪問。我們還是以 colorMaker 為例,對其代碼做適當修改來適應本節的內容。


2.1 注冊屬性

要將一個對象注冊為屬性很簡單,colorMaker 的 main.cpp 修改后如下:

#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()->setContextProperty("colorMaker", new ColorMaker);
    
    viewer.setMainQmlFile(QStringLiteral("qml/colorMaker/main.qml"));
    viewer.showExpanded();
 
    return app.exec();
}

注意我在 viewer 變量后增加的新語句:

viewer.rootContext()->setContextProperty("colorMaker", new ColorMaker);

正式這行代碼從堆上分配了一個 ColorMaker 對象,然后注冊為 QML 上下文的屬性,起了個名字就叫 colorMaker 。

viewer.rootContext()返回的是 QQmlContext 對象。 QQmlContext 類代表一個 QML 上下文,它的setContextProperty()方法可以為該上下文設置一個全局可見的屬性。要注意的是,你 new 出來的對象, QQmlContext 只是使用,不會幫你刪除,你需要自己找一個合適的時機來刪除它。

還有一點要說明,因為我們去掉了qmlRegisterType()調用,所以在 main.qml 中不能再訪問 ColorMaker 類了,比如你不能通過類名來引用它定義的 GenerateAlgorithm 枚舉類型, colorMaker.setAlgorithm(ColorMaker.LinearIncrease)語句會導致下面的報錯:

ReferenceError: ColorMaker is not defined

現在來看如何在 QML 中使用我們導出的屬性


2.2 在 QML 中使用關聯到 C++ 對象的屬性

一旦調用 setContextProperty() 導出了屬性,就可以在 QML 中使用了,不需要 import 語句哦。下面是 main.qml 修改后的代碼:

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

main.qml 代碼主要修改了三處,我已經使用方括號標注出來了。因為我將導出的屬性命名為 colorMaker ,和導出 ColorMaker 類時構造的實例的 id 一樣,所以改動少了些。

你看到了,導出的屬性可以直接使用,與屬性關聯的對象,它的信號、槽、可調用方法(使用 Q_INVOKABLE 宏修飾的方法)、屬性都可以使用,只是不能通過類名來引用枚舉值了。


參考:

《Qt Quick核心編程》第11章

Qt Quick 之 QML 與 C++ 混合編程詳解



免責聲明!

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



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