C++与QML交互总结二

目录

1.CPP调用QML

1.1 QMetaObject::invokeMethod调用

1.2 CPP中的信号绑定qml中的槽

2.QML调用CPP

2.1 QML单实例注册

2.2 将类对象注册到QML的上下文中

2.3 QML信号调用CPP槽

3.QML中注入一个cpp实例

3.1qmlRegisterType

3.2QML_ELEMENT

4.附加属性: QML_ATTACHED


以前写过一篇C++和QML交互的的文章(C++与QML交互总结_qml和c++交互_hsy12342611的博客-CSDN博客),很多网友都在看并提出了一些疑问,本篇结合网上的资料从另外一个角度再重新梳理一下C++与QML的交互。

1.CPP调用QML

1.1 QMetaObject::invokeMethod调用

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

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

    //cpp调用qml指定对象的指定方法
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto label = rootObj.first()->findChild<QObject*>("qml_label");

    // 通过元对象调用
    QVariant ret;
    QMetaObject::invokeMethod(label, "getText",
                              Q_RETURN_ARG(QVariant, ret),
                              Q_ARG(QVariant, " hello"));

    qDebug() << ret.toString();

    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Label {
            objectName: "qml_label"
            text: "QML Label"
            font.pixelSize: 25

            function getText(data) {
                return text + data
            }
        }
    }

}

1.2 CPP中的信号绑定qml中的槽

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include <QAbstractButton>
#include <QPushButton>
#include "person.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    // 先在上下文注入,再加载
    engine.load(url);

    //cpp获取qml中的指定对象
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto button = rootObj.first()->findChild<QObject*>("qml_button");
    // 使用QT4的方式绑定信号和槽: qml的信号,cpp的槽
    QObject::connect(button, SIGNAL(clicked()), &person, SLOT(clickButton()));
    QObject::connect(button, SIGNAL(coutNum(int)), &person, SLOT(clickCal(int)));
    /*
    // 使用QT5的方式绑定信号和槽不可行,此处button is nullptr
    auto button = rootObj.first()->findChild<QPushButton*>("qml_button");
    if (!button) {
        qDebug() << "button is nullptr";
    }
    QObject::connect(button, &QAbstractButton::clicked, &person, &Person::clickButton);
    */


    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0
import QtQml 2.15


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: "QML button"
            font.pixelSize: 25
            property int cal: 1
            // qml中自定义信号
            signal coutNum(int num)

            onClicked: {
                OtPerson.showInfo()
                if (0 == cal++ % 10) {
                    coutNum(cal)
                }
            }

            // cpp的信号绑定qml的槽
            Connections {
                target: OtPerson
                function onQmlCall() {
                    console.log("cpp call qml")
                }
            }

            Connections {
                target: OtPerson
                function onQmlCall(data) {
                    console.log("cpp call qml " + data)
                }
            }
        }
    }

}

2.QML调用CPP

2.1 QML单实例注册

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include "person.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);
    // qml单实例注册
    qmlRegisterSingletonInstance("PersonMudle", 1, 0, "MyPerson", &person);

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

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0
import PersonMudle 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: "QML button"
            font.pixelSize: 25

            onClicked: {
                MyPerson.showInfo()
            }
        }
    }

}

2.2 将类对象注册到QML的上下文中

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include "person.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: "QML button"
            font.pixelSize: 25

            onClicked: {
                OtPerson.showInfo()
            }
        }
    }

}

2.3 QML信号调用CPP槽

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include <QAbstractButton>
#include <QPushButton>
#include "person.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    //cpp获取qml中的指定对象
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto button = rootObj.first()->findChild<QObject*>("qml_button");
    // 使用QT4的方式绑定信号和槽: qml的信号,cpp的槽
    QObject::connect(button, SIGNAL(clicked()), &person, SLOT(clickButton()));
    QObject::connect(button, SIGNAL(coutNum(int)), &person, SLOT(clickCal(int)));
    /*
    // 使用QT5的方式绑定信号和槽不可行,此处button is nullptr
    auto button = rootObj.first()->findChild<QPushButton*>("qml_button");
    if (!button) {
        qDebug() << "button is nullptr";
    }
    QObject::connect(button, &QAbstractButton::clicked, &person, &Person::clieckButton);
    */


    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: "QML button"
            font.pixelSize: 25
            property int cal: 1
            // qml中自定义信号
            signal coutNum(int num)

            onClicked: {
                OtPerson.showInfo()
                if (0 == cal++ % 10) {
                    coutNum(cal)
                }
            }
        }
    }

}

3.QML中注入一个cpp实例

3.1qmlRegisterType

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include <QAbstractButton>
#include <QPushButton>
#include "person.h"
#include "tree.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    // 注册一个C++类型到qml中
    qmlRegisterType<Tree>("TreeMudle", 1, 0, "MyTree");

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    // 先在上下文注入,再加载
    engine.load(url);

    //cpp获取qml中的指定对象
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto button = rootObj.first()->findChild<QObject*>("qml_button");
    // 使用QT4的方式绑定信号和槽: qml的信号,cpp的槽
    QObject::connect(button, SIGNAL(clicked()), &person, SLOT(clickButton()));
    QObject::connect(button, SIGNAL(coutNum(int)), &person, SLOT(clickCal(int)));
    /*
    // 使用QT5的方式绑定信号和槽不可行,此处button is nullptr
    auto button = rootObj.first()->findChild<QPushButton*>("qml_button");
    if (!button) {
        qDebug() << "button is nullptr";
    }
    QObject::connect(button, &QAbstractButton::clicked, &person, &Person::clickButton);
    */


    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0
import QtQml 2.15
import TreeMudle 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: tree.name + tree.age + tree.date//Qt.formatDate(tree.date, "yyyy-MM-dd hh:mm:ss")
            font.pixelSize: 25
            property int cal: 1
            // qml中自定义信号
            signal coutNum(int num)

            onClicked: {
                OtPerson.showInfo()
                if (0 == cal++ % 10) {
                    coutNum(cal)
                }
                tree.name = "李四"
            }

            // cpp的信号绑定qml的槽
            Connections {
                target: OtPerson
                function onQmlCall() {
                    console.log("cpp call qml")
                }
            }

            Connections {
                target: OtPerson
                function onQmlCall(data) {
                    console.log("cpp call qml " + data)
                }
            }
        }

        // 使用cpp注入的类型
        MyTree {
            id: tree
            name: 'My_Tree'
            age: 110
            date: new Date()

            onNameChanged: {
                console.log("changed name: " + name)

            }
        }
    }

}

3.2QML_ELEMENT

.pro

QT += quick

QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17 qmltypes

QML_IMPORT_NAME = TreeMudle
QML_IMPORT_MAJOR_VERSION = 1

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp \
        person.cpp \
        tree.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    person.h \
    tree.h

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include <QAbstractButton>
#include <QPushButton>
#include "person.h"
#include "tree.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    // 先在上下文注入,再加载
    engine.load(url);

    //cpp获取qml中的指定对象
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto button = rootObj.first()->findChild<QObject*>("qml_button");
    // 使用QT4的方式绑定信号和槽: qml的信号,cpp的槽
    QObject::connect(button, SIGNAL(clicked()), &person, SLOT(clickButton()));
    QObject::connect(button, SIGNAL(coutNum(int)), &person, SLOT(clickCal(int)));
    /*
    // 使用QT5的方式绑定信号和槽不可行,此处button is nullptr
    auto button = rootObj.first()->findChild<QPushButton*>("qml_button");
    if (!button) {
        qDebug() << "button is nullptr";
    }
    QObject::connect(button, &QAbstractButton::clicked, &person, &Person::clickButton);
    */


    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0
import QtQml 2.15
import TreeMudle 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: tree.name + tree.age + tree.date//Qt.formatDate(tree.date, "yyyy-MM-dd hh:mm:ss")
            font.pixelSize: 25
            property int cal: 1
            // qml中自定义信号
            signal coutNum(int num)

            onClicked: {
                OtPerson.showInfo()
                if (0 == cal++ % 10) {
                    coutNum(cal)
                }
                tree.name = "李四"
            }

            // cpp的信号绑定qml的槽
            Connections {
                target: OtPerson
                function onQmlCall() {
                    console.log("cpp call qml")
                }
            }

            Connections {
                target: OtPerson
                function onQmlCall(data) {
                    console.log("cpp call qml " + data)
                }
            }
        }

        // 使用cpp注入的类型
        Tree {
            id: tree
            name: 'My_Tree'
            age: 110
            date: new Date()

            onNameChanged: {
                console.log("changed name: " + name)

            }
        }
    }

}

person.h

#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QString>
#include "tree.h"

class Person : public QObject
{
    Q_OBJECT
    //类的附加属性
    QML_ATTACHED(Tree)

public:
    explicit Person(QObject *parent = nullptr);
    Person(QString name, int age);
    // 想要让QML调用函数,函数要加上宏Q_INVOKABLE
    Q_INVOKABLE void showInfo() const noexcept;

public slots:
    void clickButton() const noexcept;
    void clickCal(int data) const noexcept;

signals:
    void qmlCall() const;
    // cpp给qml传参数不是所有类型都可以,一般就字符串,json和基本类型可以
    void qmlCall(QString) const;

private:
    QString _name;
    int _age;

};

#endif // PERSON_H

person.cpp

#include "person.h"
#include <QDebug>

Person::Person(QObject *parent)
    : QObject{parent}
{

}

Person::Person(QString name, int age) {
    _name = name;
    _age = age;
}

void Person::showInfo() const noexcept {
    qDebug() << "name: " << _name << ", age: "<< _age;

    // cpp发送信号调用qml中的槽
    emit qmlCall();
    emit qmlCall("王五");
}

void Person::clickButton() const noexcept {
    qDebug() << __FUNCTION__ << " in qml: click button";
}

void Person::clickCal(int data) const noexcept {
    qDebug() << __FUNCTION__ << "  " << data;
}

tree.h

#ifndef TREE_H
#define TREE_H

#include <QObject>
#include <QDate>
#include <QtQml>

//使用QML_ELEMENT后,就会产生元数据类型:描述数据的数据

class Tree : public QObject
{
    Q_OBJECT
    // qml中使用cpp类的属性
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QDate date READ getDate WRITE setDate NOTIFY dateChanged)

    QML_ELEMENT

public:
    explicit Tree(QObject *parent = nullptr);
    Tree(QString nme, qint32 age, QDate date);

    void setName(QString name) noexcept;
    void setAge(qint32 age) noexcept;
    void setDate(QDate date) noexcept;

    QString getName() const noexcept;
    qint32 getAge() const noexcept;
    QDate getDate() const noexcept;

signals:
    void nameChanged(QString);
    void ageChanged();
    void dateChanged();

private:
    QString _name;
    qint32 _age;
    QDate _date;
};

#endif // TREE_H

tree.cpp

#include "tree.h"

Tree::Tree(QObject *parent)
    : QObject{parent}
{

}

Tree::Tree(QString name, qint32 age, QDate date) {
    _name = name;
    _age = age;
    _date = date;
}

void Tree::setName(QString name) noexcept {
    _name = name;
    emit nameChanged(name);
}

void Tree::setAge(qint32 age) noexcept {
    _age = age;
    emit ageChanged();
}

void Tree::setDate(QDate date) noexcept {
    _date = date;
    emit dateChanged();
}

QString Tree::getName() const noexcept {
    return _name;
}

qint32 Tree::getAge() const noexcept {
    return _age;
}

QDate Tree::getDate() const noexcept {
    return _date;
}

4.附加属性: QML_ATTACHED

使用附加属性:本质上会创建一个附加属性对象

效果如下:

tree.h

#ifndef TREE_H
#define TREE_H

#include <QObject>
#include <QDate>
#include <QtQml>

//使用QML_ELEMENT后,就会产生元数据类型:描述数据的数据

class Tree : public QObject
{
    Q_OBJECT
    // qml中使用cpp类的属性
    Q_PROPERTY(QString name READ getName WRITE setName NOTIFY nameChanged)
    Q_PROPERTY(int age READ getAge WRITE setAge NOTIFY ageChanged)
    Q_PROPERTY(QDate date READ getDate WRITE setDate NOTIFY dateChanged)

    QML_ANONYMOUS

public:
    explicit Tree(QObject *parent = nullptr);
    Tree(QString nme, qint32 age, QDate date);

    void setName(QString name) noexcept;
    void setAge(qint32 age) noexcept;
    void setDate(QDate date) noexcept;

    QString getName() const noexcept;
    qint32 getAge() const noexcept;
    QDate getDate() const noexcept;

signals:
    void nameChanged(QString);
    void ageChanged();
    void dateChanged();

private:
    QString _name;
    qint32 _age;
    QDate _date;
};

#endif // TREE_H

tree.cpp

#include "tree.h"

Tree::Tree(QObject *parent)
    : QObject{parent}
{

}

Tree::Tree(QString name, qint32 age, QDate date) {
    _name = name;
    _age = age;
    _date = date;
}

void Tree::setName(QString name) noexcept {
    _name = name;
    emit nameChanged(name);
}

void Tree::setAge(qint32 age) noexcept {
    _age = age;
    emit ageChanged();
}

void Tree::setDate(QDate date) noexcept {
    _date = date;
    emit dateChanged();
}

QString Tree::getName() const noexcept {
    return _name;
}

qint32 Tree::getAge() const noexcept {
    return _age;
}

QDate Tree::getDate() const noexcept {
    return _date;
}

person.h

#ifndef PERSON_H
#define PERSON_H

#include <QObject>
#include <QString>
#include "tree.h"

class Person : public QObject
{
    Q_OBJECT
    //类的附加属性,将Tree中的属性附加到Person类中
    QML_ATTACHED(Tree)
    QML_ELEMENT

public:
    explicit Person(QObject *parent = nullptr);
    Person(QString name, int age);
    // 想要让QML调用函数,函数要加上宏Q_INVOKABLE
    Q_INVOKABLE void showInfo() const noexcept;

public slots:
    void clickButton() const noexcept;
    void clickCal(int data) const noexcept;

    static Tree* qmlAttachedProperties(QObject*);

signals:
    void qmlCall() const;
    // cpp给qml传参数不是所有类型都可以,一般就字符串,json和基本类型可以
    void qmlCall(QString) const;

private:
    QString _name;
    int _age;

};

#endif // PERSON_H

person.cpp

#include "person.h"
#include <QDebug>

Person::Person(QObject *parent)
    : QObject{parent}
{

}

Person::Person(QString name, int age) {
    _name = name;
    _age = age;
}

void Person::showInfo() const noexcept {
    qDebug() << "name: " << _name << ", age: "<< _age;

    // cpp发送信号调用qml中的槽
    emit qmlCall();
    emit qmlCall("王五");
}

void Person::clickButton() const noexcept {
    qDebug() << __FUNCTION__ << " in qml: click button";
}

void Person::clickCal(int data) const noexcept {
    qDebug() << __FUNCTION__ << "  " << data;
}

Tree* Person::qmlAttachedProperties(QObject* obj) {
    qDebug() << __FUNCTION__ << obj;
    return new Tree(obj);
}

main.cpp

#include <QGuiApplication>
#include <QQmlApplicationEngine>
// 元对象头文件
#include <QMetaObject>
#include <QDebug>
#include <QQmlContext>
#include <QAbstractButton>
#include <QPushButton>
#include "person.h"
#include "tree.h"


int main(int argc, char *argv[])
{
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
    QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
#endif
    QGuiApplication app(argc, argv);

    Person person("张三", 18);

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

    //上下文: 将类对象注册到QML的上下文背景中
    auto ctext = engine.rootContext();
    ctext->setContextProperty("OtPerson", &person);

    // 先在上下文注入,再加载
    engine.load(url);

    //cpp获取qml中的指定对象
    auto rootObj = engine.rootObjects();
    // rootObj.first()获取所有对象列表
    auto button = rootObj.first()->findChild<QObject*>("qml_button");
    // 使用QT4的方式绑定信号和槽: qml的信号,cpp的槽
    QObject::connect(button, SIGNAL(clicked()), &person, SLOT(clickButton()));
    QObject::connect(button, SIGNAL(coutNum(int)), &person, SLOT(clickCal(int)));
    /*
    // 使用QT5的方式绑定信号和槽不可行,此处button is nullptr
    auto button = rootObj.first()->findChild<QPushButton*>("qml_button");
    if (!button) {
        qDebug() << "button is nullptr";
    }
    QObject::connect(button, &QAbstractButton::clicked, &person, &Person::clickButton);
    */


    return app.exec();
}

main.qml

import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15 as QtCtrl
import QtQuick.Layouts 1.0
import QtQml 2.15
import PersonMudle 1.0


Window {
    width: 640
    height: 480
    visible: true
    title: qsTr("qml和cpp交互总结")

    Item {
        id: item
        anchors.fill: parent

        QtCtrl.Button {
            objectName: "qml_button"
            text: Person.name + Person.age + Person.date
            font.pixelSize: 25
            property int cal: 1
            // qml中自定义信号
            signal coutNum(int num)

            onClicked: {
                OtPerson.showInfo()
                if (0 == cal++ % 10) {
                    coutNum(cal)
                }
                console.log(Person.name + " " + Person.age + " " + Person.date)
                console.log(this)
            }

            // cpp的信号绑定qml的槽
            Connections {
                target: OtPerson
                function onQmlCall() {
                    console.log("cpp call qml")
                }
            }

            Connections {
                target: OtPerson
                function onQmlCall(data) {
                    console.log("cpp call qml " + data)
                }
            }

            // 使用附加属性:本质上会创建一个附加属性对象
            Person.name: "赵六"
            Person.age: 25
            Person.date: new Date()
        }
    }

}

.pro

QT += quick

QT += core gui
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

CONFIG += c++17 qmltypes

QML_IMPORT_NAME = PersonMudle
QML_IMPORT_MAJOR_VERSION = 1

# You can make your code fail to compile if it uses deprecated APIs.
# In order to do so, uncomment the following line.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000    # disables all the APIs deprecated before Qt 6.0.0

SOURCES += \
        main.cpp \
        person.cpp \
        tree.cpp

RESOURCES += qml.qrc

# Additional import path used to resolve QML modules in Qt Creator's code model
QML_IMPORT_PATH =

# Additional import path used to resolve QML modules just for Qt Quick Designer
QML_DESIGNER_IMPORT_PATH =

# Default rules for deployment.
qnx: target.path = /tmp/$${TARGET}/bin
else: unix:!android: target.path = /opt/$${TARGET}/bin
!isEmpty(target.path): INSTALLS += target

HEADERS += \
    person.h \
    tree.h

猜你喜欢

转载自blog.csdn.net/hsy12342611/article/details/133309866