目录
1.1 QMetaObject::invokeMethod调用
以前写过一篇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