QML调用CPP函数
要求:
- 使用 Q_OBJECT 宏需要继承 QObject 类。Q_OBJECT能够启用信号和槽机制、使用动态属性系统。(使用 Q_OBJECT 宏的类需要通过Qt的元对象编译器(moc)进行处理。)
- 使用 Q_INVOKABLE 修饰要暴露给 QML 的函数。
1.在main.cpp中进行注册
// 注册c++类到qml 参数分别为导入的 模块名称 主版本号 次版本号 模块名称
qmlRegisterType<CppObject>("CppObject",1,0,"CppObject");
2.在qml中导入
import CppObject 1.0
CppObject{
id:cppobj
}
3.通过id+方法名的方式调用
// 加上这个宏,当前函数就可以被qml访问调用
Q_INVOKABLE void func();
//test.h
#ifndef TEST_H
#define TEST_H
#include <QObject>
#include "QDebug"
class CppObject : public QObject
{
Q_OBJECT
public:
explicit CppObject(QObject *parent = nullptr);
//通过宏定义在qml使用cpp类中的函数
Q_INVOKABLE void print_(QString str)
{
qDebug() << str;
}
};
#endif // TEST_H
//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLocale>
#include <QTranslator>
#include "test.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);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "untitled_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
app.installTranslator(&translator);
break;
}
}
//主要是这里其他的都是默认的
// 注册c++类到qml 参数分别为导入的 模块名称 主版本号 次版本号 模块名称
qmlRegisterType<CppObject>("CppObject",1,0,"CppObject");
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
import CppObject 1.0
Window {
id: win
width: 800
height: 600
visible: true
title: qsTr("Hello World")
CppObject{
id:cppobj
}
Button{
width: 50
height: 50
background: Rectangle{
color:"red"
}
onClicked: {
//obj.printMsg()
cppobj.print_("test")
}
}
}
定义全局变量,注册到上下文
样例:
#include <QQmlContext>
QQmlApplicationEngine engine;
//这两句是重点,设置全局变量
QQmlContext *context = engine.rootContext();
context->setContextProperty("SCREEN_WIDTH", 800);
也可以用此方法将类对象暴露给QML
setContextProperty两个参数表示的意义为:
- 第一个参数表示 qml 可以识别的对象名
- 第二个参数表示 C++ 对象
#include <QtQml/QQmlContext>
#include "vacUdpClient.h"
/*** main.cpp ***/
vacUdpClient udpclient;
QQmlContext* context = engine.rootContext();
context->setContextProperty("udpclient", &udpclient);
使用时候当变量用就行,SCREEN_WIDTH
为变量名
//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLocale>
#include <QTranslator>
//全局变量必须得头文件
#include <QQmlContext>
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);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "untitled_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
app.installTranslator(&translator);
break;
}
}
QQmlApplicationEngine engine;
//这两句是重点,设置全局变量
QQmlContext *context = engine.rootContext();
context->setContextProperty("SCREEN_WIDTH", 800);
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
Window {
id: window
visible: true
//使用全局变量
width: SCREEN_WIDTH
height: 500
title: qsTr("Hello World")
Button{
width: 100
height: 100
background: {
color:"black"
}
}
}
CPP访问QML函数
//main.cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QLocale>
#include <QTranslator>
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);
QTranslator translator;
const QStringList uiLanguages = QLocale::system().uiLanguages();
for (const QString &locale : uiLanguages) {
const QString baseName = "untitled_" + QLocale(locale).name();
if (translator.load(":/i18n/" + baseName)) {
app.installTranslator(&translator);
break;
}
}
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);
//重点
auto list = engine.rootObjects();
auto window = list.first();
QVariant res;
QVariant arg_1 = 123;
QVariant arg_2 = "zhangsan";
QMetaObject::invokeMethod(window, "qmlFunc",Q_RETURN_ARG(QVariant, res),Q_ARG(QVariant, arg_1),Q_ARG(QVariant, arg_2));
qDebug() << "res = " << res;
return app.exec();
}
//main.qml
import QtQuick 2.15
import QtQuick.Window 2.15
import QtQuick.Controls 2.15
Window {
id: window
visible: true
width: SCREEN_WIDTH
height: 500
title: qsTr("Hello World")
//供C++端调用的函数
function qmlFunc(i, s) {
return "success"
}
}
单实例注册类
main.cpp文件里加这个
// qml单实例注册
qmlRegisterSingletonInstance("PersonMudle", 1, 0, "MyPerson", &person);
以下这样使用
import PersonMudle 1.0
Button {
objectName: "qml_button"
text: "QML button"
font.pixelSize: 25
onClicked: {
MyPerson.showInfo()
}
}
信号与槽
qml信号 cpp槽函数
//加在main.cpp中
// engine 加载完成后 load以后
auto list = engine.rootObjects();
//auto objName = list.first()->objectName(); // 获取第一个objname
//auto mybuttonObj = list.first()->findChild<QObject *>("mybutton");
auto window = list.first();
//槽函数链接
// 第一个参数为组件
// 第二个为信号名
// 第三个为类的实例化
// 第三个为槽函数
QObject::connect(window,SIGNAL(qmlSig(int,QString)),
CppObject::getInstance(),SLOT(cppSlot(int,QString)));
例子:
//类
Person person("张三", 18);
//上下文: 将类对象注册到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)));
//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)
}
}
}
}
}
cpp信号 qml槽函数
//信号开头要小写
void setCardData(QString str);
//上下文: 将类对象注册到QML的上下文背景中
engine.rootContext()->setContextProperty("camera",&camera);
Connections {
//这是注册到qml中的c++类的名字
target: camera
//这里就是信号对应的槽函数的名字,把函数名设置为on+信号名,就能自动识别是哪个信号,括号内是信号传的参数,只说明参数名(方便在槽函数中使用)不用说明类型
function onSetCardData(res){
//操作
label_showdb.text = res
console.log("success")
}
}