C++与QML交互总结二

news2024/11/26 11:31:10

目录

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

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1042690.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

了解MES:提升制造业的效率与竞争力

今天我将和大家分享关于MES&#xff08;Manufacturing Execution System&#xff0c;制造执行系统&#xff09;的知识。随着制造业的发展和变革&#xff0c;MES作为一个关键的信息技术工具&#xff0c;已经成为许多企业提升效率和竞争力的重要策略之一。 MES的定义与作用 MES是…

孟晚舟最新发声!华为吹响人工智能的号角,发布“全面智能化”战略部署

原创 | 文 BFT机器人 1、华为孟晚舟新发声&#xff0c;华为发布“全面智能化”战略 上周三&#xff08;9月30号&#xff09;上午&#xff0c;华为全联接大会2023正式在上海举行&#xff0c;作为华为副董事长、轮值董事长、CFO的孟晚舟代表华为再次发声&#xff01;在演讲上&am…

数值微分比较

对于序列 { x n } x 1 , x 2 , ⋯ , x n \{x_n\} x_1, x_2, \cdots, x_n {xn​}x1​,x2​,⋯,xn​&#xff0c;求其导数 { x n ′ } \{x_n\} {xn′​}。 一、精度 O ( h ) O(h) O(h) x k ′ { x 2 − x 1 h , k 1 x k − x k − 1 h , k 2 , 3 , ⋯ , n x_k \begin{ca…

优化多设备体验,让您的应用为 Samsung 全新设备做好准备

作者 / Android 开发者关系团队总监 Maru Ahues Bouza 从可折叠设备创新到无缝连接&#xff0c;Google 和 Samsung 一直携手合作&#xff0c;致力于打造适用于 Android 手机、平板电脑、智能手表等设备的实用体验。近期&#xff0c;在首尔举行的 Galaxy Unpacked 发布会上&…

权威认可!安全狗获CNVD“漏洞信息报送贡献单位”殊荣

9月24日&#xff0c;国家信息安全漏洞共享平台公布了2022年度CNVD支撑单位年度工作情况及优秀单位个人表彰名单。 作为国内云原生安全领导厂商&#xff0c;安全狗入选漏洞信息报送贡献单位。 厦门服云信息科技有限公司&#xff08;品牌名&#xff1a;安全狗&#xff09;成立于2…

C++,模板 /泛型(添加)

4、非类型函数模板参数 模板元编程是一种通过在编译时执行代码来生成程序的技术。它利用C模板系统的强大功能&#xff0c;在编译阶段进行计算和推导&#xff0c;支持的类型只有整型。 例1&#xff1a; 例2&#xff1a; 可以有默认值,当有多个默认值时&#xff0c;要全部位于最…

BUUCTF刷题十一道(09)

文章目录 October 2019 Twice SQL Injection[GYCTF2020]EasyThinking[BJDCTF2020]EzPHP[HFCTF2020]JustEscape(vm2沙箱逃逸)[GXYCTF2019]StrongestMind[GKCTF 2021]easycms[SUCTF 2018]GetShell[b01lers2020]Life on Mars[WMCTF2020]Make PHP Great Again[MRCTF2020]Ezaudit[CS…

奥迪 Q7 e-tron | 无法通过插电式充电器充电

虽然电动汽车似乎是未来的方向&#xff0c;但插电式混合动力车辆在实现最佳两全之间似乎是当下的主流。这类车辆可以纯电动驾驶&#xff0c;满足当前城市的低排放规定&#xff0c;然而&#xff0c;在内燃机的支持下&#xff0c;我们可以无缝地行驶&#xff0c;充分利用无需担心…

WebDAV之π-Disk派盘 + 纸间书摘

纸间书摘是专为喜欢做读书笔记的小伙伴量身打造的专属书摘app,不仅仅可以从别的app中导入图书,并且还能来帮助你选择性复制可以来轻松的搞定哦 所有功能完全免费,没有广告,不限制识别次数。 多种备份,本地备份和基于WebDAV协议的云端备份。 丰富的书摘导出功能,用户可…

求职应聘,在线测评要不要真实的去做?

求职的朋友们&#xff0c;今年的行情不容乐观&#xff0c;所以要更加努力才能争取到理想的工作岗位。找工作是一个不衰的话题&#xff0c;不仅仅是大学毕业生们&#xff0c;职场人都绕不过去的话题。 如今越来越的企业采用在线测评&#xff0c;在知乎上很多盆友都遇到了&…

多线程的死锁问题

可重入和不可重入&#x1f60a;&#x1f60a;&#x1f60a; 一个线程针对同一个对象,连续加锁两次,是否会有问题 ~~ 如果没问题,就叫可重入的.如果有问题,就叫不可重入的. 代码示例&#x1f349;&#x1f349;&#x1f349;: synchronized public void add(){synchronized (…

Mixin和HTX遭黑客攻击!后者全赔,前者只赔50%引投资者不满?

资产安全一直都是区块链老生常谈的话题&#xff0c;而最近一系列安全事件频发引起了投资者的担忧&#xff0c;先是V神的推特账号被盗&#xff0c;再是亿万富翁马克库班 (Mark Cuban) 的小狐狸钱包被攻击&#xff0c;如今&#xff0c;黑客又盯上了承载大量资金的加密机构。 9月2…

如何提取音频中的纯人声?新手也能快速掌握

在数字媒体时代&#xff0c;无论是音乐、电影还是短视频制作&#xff0c;音频处理都是一个不可或缺的技能&#xff0c;尤其是人声提取部分&#xff0c;今天就来教大家怎样在一段音频中把人声部分提取出来&#xff0c;新手也能快速掌握&#xff01; 第一步&#xff1a;打开【音分…

(手撕)快速排序 ----->c语言实现 +图解

目录 目录&#xff1a; 1:快速排序的思想 2:快速排序的三种形式 3:快速排序的优化方法 前言&#xff1a;快速排序是一种非常重要的排序我们需要掌握它&#xff0c;当然肯定也相比前面的那些排序有一定的难度&#xff0c;但是相信本篇文章会让你对快排有重新的理解&#xff0c;…

vue3 + mark.js | 实现文字标注功能

页面效果 具体实现 新增 1、监听鼠标抬起事件&#xff0c;通过window.getSelection()方法获取鼠标用户选择的文本范围或光标的当前位置。2、通过 选中的文字长度是否大于0或window.getSelection().isCollapsed (返回一个布尔值用于描述选区的起始点和终止点是否位于一个位置&…

TensorFlow入门(三、TensorFlow模型的运行机制)

TensorFlow通过"图"和会话的方式分离了计算的定义和执行,即它的运行机制是"定义"与"运行"相分离的。从操作层面可以把它抽象成两种:模型构建和模型运行。 TensorFlow模型中的几个概念: ①张量(tensor):数据,即某一类型的多维数组 ②变量(Vari…

Wi-Fi直连分享:Android设备间的高速连接

Wi-Fi直连分享&#xff1a;Android设备间的高速连接 引言 随着无线局域网&#xff08;Wi-Fi&#xff09;的普及和发展&#xff0c;使用Wi-Fi直连技术&#xff08;P2P&#xff09;在没有中间接入点的情况下实现设备间直接互联成为可能。通过Wi-Fi直连&#xff0c;具备相应硬件…

链动2+1模式:如何用二级分销打造高效团队,实现销量突破

你是否想要拥有一个高效的团队&#xff0c;让你的销量快速提升&#xff1f;你是否厌倦了传统的多层级分销模式&#xff0c;觉得它太复杂、太难管理、太不合规&#xff1f;你是否想要找到一种简单、合理、合法的商业模式&#xff0c;让你的收益稳定、可持续、可复制&#xff1f;…

【深度学习实验】卷积神经网络(三):自定义二维卷积神经网络:步长和填充、输入输出通道

目录 一、实验介绍 二、实验环境 1. 配置虚拟环境 2. 库版本介绍 三、实验内容 0. 导入必要的工具包 1. 步长、填充 a. 二维互相关运算&#xff08;corr2d&#xff09; b. 二维卷积层类&#xff08;Conv2D&#xff09; c. 模型测试 d. 代码整合 2. 输入输出通道 a…

前缀树-Trie树

前缀树—Trie树&#xff0c;也叫作“单词查找树”、“字典树” 它属于多叉树结构&#xff0c;典型应用是用于统计&#xff0c;排序和保存大量的字符串&#xff08;但不仅限于字符串&#xff09;&#xff0c;所以经常被搜索引擎系统用于文本词频统计。它的优点是&#xff1a;利…