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个工程
在这里插入图片描述

相关文章
相关标签/搜索