Qt Quick入門教程(11) : qml C++交互介紹

在Qt界面開發時,用信號槽能夠很容易實現各個窗口控件之間的交互,qml也是能夠的,qml和C++能夠相互調用,能夠在qml代碼中調用C++的類對象,也能夠用C++類來獲取qml的控件對象,下面分別介紹這兩這種用法,須要源碼的能夠翻到最後直接下載。html

1、qml調用C++

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

​ 方式1:在C+中實現一個類,註冊爲 QML 環境的一個類型,在 QML 環境中使用該類型建立對象。app

​ 方式2:在 C++中構造一個對象,將這個對象設置爲 QML 的上下文屬性,在QML 環境中直接使用該屬性。ide

​ 無論哪一種方式,對要導出的 C++類都有要求,不是一個類的全部方法、變量均可以在 QML 語境中使用,定義能夠導出的 C++類
前提條件
要想將一個類或對象導出到 QML 中,下列的前提條件必須知足∶函數

(1)從 QObject 或 QObject 的派生類繼承,並使用Q_OBJECT宏,這和使用信號與槽的前提條件同樣的,這兩個條件是爲了讓一個類可以進入Qt強大的元對象系統(meta-object system)中,只有使用元對象系統,一個類的某些方法或屬性纔可能經過字符串形式的名字來調用,才能夠在 QML 中被訪問。ui

(2)成員函數想在qml中被調用,則須要在聲明前加上Q_INVOKABLEurl

(3)槽函數能夠用類對象在qml代碼中直接調用指針

(4)C++的成員屬性能夠用Q_PROPERTY宏設置code

(5)枚舉體須要用Q_ENUMS導出htm

下面介紹方式1, 例以下面這個類

#ifndef TESTBOX_H
#define TESTBOX_H

#include <QObject>

class TestBox : public QObject
{
    Q_OBJECT
    Q_ENUMS(ColorType)
    Q_PROPERTY(int mValue READ getValue WRITE setValue)

public:
    explicit TestBox(QObject *parent = nullptr);

    enum ColorType
    {
        Red,
        Green,
        Blue
    };

    // 成員函數想在qml中被調用,則須要在聲明前加上Q_INVOKABLE
    Q_INVOKABLE int fun1();

    int getValue()
    {
        return m_value;
    }

    Q_INVOKABLE void setValue(int value)
    {
        m_value = value;
    }

signals:
    void sig_Value();

public slots:
    void on_Get();

private:
    int m_value = 0;
};

#endif // TESTBOX_H

類定義好後,在main.cpp中註冊

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "testbox.h"

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    qmlRegisterType<TestBox>("cpp.qt.TestBox", 1, 0, "TestBox");

    QQmlApplicationEngine engine;
    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

調用qmlRegisterType註冊類TestBox,版本是1.0, 這個版本號能夠本身定義。

最後在qml代碼中調用

import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.5
import cpp.qt.TestBox 1.0

Window {
    visible: true
    width: 640
    height: 480
    title: qsTr("Hello World")

    TestBox{
        id:tb
        mValue:123  //能夠在這裏給對象賦值
    }

    Button{
        id:btn1
        text:"getValue"
        anchors.left: parent.left
        anchors.leftMargin: 40
        anchors.top: parent.top
        anchors.topMargin: 60

        onClicked: {
            tb.on_Get()  //調用槽函數
        }
    }

    Button{
        id:btn2
        text:"setValue"
        anchors.left: btn1.left
        anchors.top: btn1.bottom
        anchors.topMargin: 20

        onClicked: {
            tb.setValue(3456)
        }
    }

    Button{
        id:btn3
        text:"getenum"
        anchors.left: btn2.left
        anchors.top: btn2.bottom
        anchors.topMargin: 10

        onClicked: {
            valueTextFeild.text = TestBox.Blue  //調用枚舉
        }
    }

    Button{
        id:btn4
        text:"invoke fun"
        anchors.left: btn3.left
        anchors.top: btn3.bottom
        anchors.topMargin: 10

        onClicked: {
            valueTextFeild.text = tb.fun1()  //調用普通成員函數
        }
    }

    TextField
    {
        id:valueTextFeild
        anchors.left: btn1.right
        anchors.leftMargin: 15
        anchors.top: btn1.top
    }

    //連接信號槽
    Connections{
        target: tb

        onSig_Value:{
            valueTextFeild.text = tb.mValue  //獲取成員屬性值
        }
    }
}

運行界面以下:
在這裏插入圖片描述

方式2:

在main.cpp中直接建立C++類對象,例以下面的代碼,

engine.rootContext()->setContextProperty("tb", new TestBox);

new對象 tb, 而後在qml中就能夠直接使用tb了。

代碼以下:

#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include "testbox.h"
#include <QQmlContext>

int main(int argc, char *argv[])
{
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);

    QGuiApplication app(argc, argv);

    //qmlRegisterType<TestBox>("cpp.qt.TestBox", 1, 0, "TestBox");

    QQmlApplicationEngine engine;

    engine.rootContext()->setContextProperty("tb", new TestBox);

    const QUrl url(QStringLiteral("qrc:/main.qml"));
    QObject::connect(&engine, &QQmlApplicationEngine::objectCreated,
                     &app, [url](QObject *obj, const QUrl &objUrl) {
        if (!obj && url == objUrl)
            QCoreApplication::exit(-1);
    }, Qt::QueuedConnection);
    engine.load(url);

    return app.exec();
}

這種方式有弊端,枚舉值如法直接在qml中得到,能夠用數字代替。

2、C++調用qml

在C++代碼中獲取qml控件時,須要用到objectName

Text{
        objectName: "textLabel"
        text:"Hello World"
        anchors.centerIn: parent
        font.pixelSize: 26
    }

    Button{
        objectName: "quitBtn"
        anchors.right: parent.right
        anchors.rightMargin: 10
        anchors.bottom: parent.bottom
        anchors.bottomMargin: 10
        text:qsTr("退出")
    }

​ 上面的控件在聲明時,都設置了屬性objectName, qt程序在初始化時有個對象樹,在對象樹中根據objectName調用findChild能夠獲取到控件對象指針

//C++獲取qml的控件
QObject* pQuitBtn = pRoot->findChild<QObject*>("quitBtn");
if(pQuitBtn)
{
    QObject::connect(pQuitBtn, SIGNAL(clicked()), &app, SLOT(quit()));
}

QObject *pText = pRoot->findChild<QObject*>("textLabel");
if(pText)
{
    bool bRet = QMetaObject::invokeMethod(pText, "setText", Q_ARG(QString, "AAAA"));
    qDebug() << "bRet = " << bRet; //調用失敗,沒有該方法

    pText->setProperty("color", QColor::fromRgb(255,0,0));
}

3、源碼下載

以上具體功能,能夠看個人代碼,連接以下:
https://gitee.com/qwerwo/qml_code

3個工程
在這裏插入圖片描述

相關文章
相關標籤/搜索