QML与C++交互
使用全局对象
main.cpp
cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
//全局对象,上下文对象
QQmlContext* context = engine.rootContext();
QScreen*screen = QGuiApplication::primaryScreen();
QRect rect = screen->availableGeometry();
context->setProperty("SCREEN_WIDTH",rect.width()/2 ); // 定义一个全局的属性可以给qml去使用
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
css
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
Window {
visible: true
width: SCREEN_WIDTH //从main.cpp中拿到这个变量的值
height: screen.desktopAvailableHeight/2 //screen可以获取到屏幕的相关大小。
title: qsTr("Hello World")
}
使用qmlRegisterType模板类
myobject.cpp
cpp
#include "myobject.h"
MyObject::MyObject(QObject *parent) : QObject(parent)
{
}
MyObject *MyObject::getInst()
{
static MyObject* obj = new MyObject;
return obj;
}
int MyObject::iValue() const
{
return m_iValue;
}
void MyObject::setIValue(int iValue)
{
m_iValue = iValue;
}
QString MyObject::sString() const
{
return m_sString;
}
void MyObject::setSString(const QString &sString)
{
m_sString = sString;
}
myobject.h
cpp
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QtQml>
class MyObject : public QObject
{
Q_OBJECT
// QML_ELEMENT //声明为QML元素,低版本5.12 qt没有
public:
explicit MyObject(QObject *parent = nullptr);
static MyObject* getInst();
void fun();
int iValue() const;
void setIValue(int iValue);
Q_PROPERTY(int iValue MEMBER m_iValue NOTIFY iValueChanged) //这个和下面那个都可以,经测试,使用MEMBER可以触发信号,下面的不行。
// Q_PROPERTY(int iValue READ iValue WRITE setIValue NOTIFY iValueChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。
Q_PROPERTY(QString qstr READ sString() WRITE setSString NOTIFY sStringChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。
QString sString() const;
void setSString(const QString &sString);
private:
int m_iValue; //光标定位在属性上,键盘按下Alt+Enter 选择第一个
QString m_sString;
signals:
void iValueChanged();
void sStringChanged();
};
#endif // MYOBJECT_H
main.cpp
cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include "myobject.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
//全局对象,上下文对象
QQmlContext* context = engine.rootContext();
QScreen*screen = QGuiApplication::primaryScreen();
QRect rect = screen->availableGeometry();
qDebug()<<rect.width()/2;
context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用
// context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象
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
cpp
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0
Window {
visible: true
// width: SCREEN_WIDTH //从main.cpp中拿到这个变量的值,12版本似乎拿不到。
width: screen.desktopAvailableWidth/2
height: screen.desktopAvailableHeight/2 //screen可以获取到屏幕的相关大小。
title: qsTr("Hello World")
property int val: myobj.iValue
MyObject{ //C++中的对象。
id:myobj
iValue: 1
qstr: "12"
Component.onCompleted: {
console.log("ivalue = ",myobj.iValue," qstr = ",myobj.qstr)
}
onIValueChanged: { //这个信号来自与QT中的MODIFY信号,本人测试,在cpp中使用MEMBER方式可以绑定,其他不行
console.log("iValue changed = ",iValue)
}
}
Button{
onClicked: {
myobj.iValue =100
console.log("clicked myobj.iValue = ",myobj.iValue)
}
}
onValChanged: {
console.log("val = ",val)
}
}
QML端直接访问C++的函数
需要在C++类的函数使用Q_INVOKABLE宏,就可以完成直接访问,见下图。
C++端直接调用qml函数
QML发送信号C++接收
方式一:在QML端绑定信号
main.qml
css
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0
Window {
id:window
visible: true
width:600
height: 400
title: qsTr("QML与C++交互")
signal qmlSig(int i,string s)
MyObject{ //C++中的对象。
id:myobj
iValue: 1
m_sString: "m_sString_test"
}
Button{
onClicked: {
console.log("click")
qmlSig(10,"张三") //点击发送信号,让C++端去接受他。
}
}
//方式一:
Connections{
target: window
onQmlSig:{
myobj.cppSlot(i,s) //直接调用槽函数。
}
}
// 方式二
Component.onCompleted: {
qmlSig.connect(myobj.cppSlot)
}
}
方式二:在C++端绑定信号
main.cpp
cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>
#include "myobject.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qDebug()<<QGuiApplication::platformName();
QQmlApplicationEngine engine;
//全局对象,上下文对象
QQmlContext* context = engine.rootContext();
QScreen*screen = QGuiApplication::primaryScreen();
QRect rect = screen->availableGeometry();
qDebug()<<rect.width()/2;
context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用
// context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象
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);
//engine加载完成之后
auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
//第一个元素的windows
QObject* window = list.first();
QObject* btn = list.first()->findChild<QObject*>("mybtn");
qDebug()<< window <<"|"<< window->objectName();
qDebug()<< btn <<"|"<< btn->objectName();
// 方式三
QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString)) );
// MyObject* w = MyObject::getInst();
// QObject::connect(window, &QQuickWindowQmlImpl_QML_0::qmlSig, //这里无法用qt5的信号槽连接。
// w, &MyObject::cppSlot);
return app.exec();
}
C++端发送信号绑定qml函数
方式一
main.cpp
cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>
#include "myobject.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qDebug()<<QGuiApplication::platformName();
QQmlApplicationEngine engine;
//全局对象,上下文对象
QQmlContext* context = engine.rootContext();
QScreen*screen = QGuiApplication::primaryScreen();
QRect rect = screen->availableGeometry();
qDebug()<<rect.width()/2;
context->setProperty("SCREEN_WIDTH",500 ); // 定义一个全局的属性可以给qml去使用
// context->setProperty("MyObject",MyObject::getInst()); //使用单例模式来创建一个对象。
qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //myobj qml要导入的名称,主版本,次版本,使用对象
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);
//engine加载完成之后
auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
//第一个元素的windows
QObject* window = list.first();
QObject* btn = list.first()->findChild<QObject*>("mybtn");
qDebug()<< window <<"|"<< window->objectName();
qDebug()<< btn <<"|"<< btn->objectName();
// 方式三
QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString)) );
// MyObject* w = MyObject::getInst();
// QObject::connect(window, &QQuickWindowQmlImpl_QML_0::qmlSig, //这里无法用qt5的信号槽连接。
// w, &MyObject::cppSlot);
return app.exec();
}
main.qml
cpp
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0
Window {
id:window
visible: true
width:600
height: 400
objectName: "mywindow"
title: qsTr("QML与C++交互")
signal qmlSig(int i,string s)
MyObject{ //C++中的对象。
id:myobj
iValue: 1
m_sString: "m_sString_test"
}
Button{
objectName: "mybtn"
onClicked: {
console.log("click")
// myobj.cppSig(100,"test");
myobj.fun()
}
}
Connections{
target: myobj
onCppSig:{
console.log(i,s);
}
// function onCppSig(i,s){
// qmlSlot(i,s)
// }
}
}
myobject.cpp
cpp
#include "myobject.h"
MyObject::MyObject(QObject *parent) : QObject(parent)
{
}
MyObject *MyObject::getInst()
{
static MyObject* obj = new MyObject;
return obj;
}
void MyObject::fun()
{
qDebug()<<__FUNCTION__;
emit cppSig(1,"C++");
}
int MyObject::iValue() const
{
return m_iValue;
}
void MyObject::setIValue(int iValue)
{
m_iValue = iValue;
}
QString MyObject::sString() const
{
return m_sString;
}
void MyObject::setSString(const QString &sString)
{
m_sString = sString;
}
void MyObject::cppSlot(int i, QString s)
{
qDebug()<<__FUNCTION__ <<i<< s;
}
myobject.h
cpp
#ifndef MYOBJECT_H
#define MYOBJECT_H
#include <QObject>
#include <QtQml>
class MyObject : public QObject
{
Q_OBJECT
// QML_ELEMENT //声明为QML元素,低版本5.12 qt没有
public:
explicit MyObject(QObject *parent = nullptr);
static MyObject* getInst();
Q_INVOKABLE void fun(); //Q_INVOKABLE宏可以让qml直接访问函数。
int iValue() const;
void setIValue(int iValue);
Q_PROPERTY(int iValue MEMBER m_iValue NOTIFY iValueChanged) //这个和下面那个都可以,经测试,使用MEMBER可以触发信号,下面的不行。
Q_PROPERTY(QString m_sString MEMBER m_sString NOTIFY sStringChanged) //QT宏,iValue是声明的名称,可以通过名称获取,并且创建读取和设置的函数,在新加一个值改变的信号。
QString sString() const;
void setSString(const QString &sString);
private:
int m_iValue; //光标定位在属性上,键盘按下Alt+Enter 选择第一个
QString m_sString;
public slots:
void cppSlot(int i,QString s);
signals:
void iValueChanged();
void sStringChanged();
void cppSig(int i,QString s);
};
#endif // MYOBJECT_H
方式二
main.cpp
cpp
#include <QGuiApplication>
#include <QQmlApplicationEngine>
#include <QQmlContext>
#include <QScreen>
#include <QRect>
#include <QtDebug>
#include <QObject>
#include "myobject.h"
int main(int argc, char *argv[])
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
QGuiApplication app(argc, argv);
qDebug()<<QGuiApplication::platformName();
QQmlApplicationEngine engine;
qmlRegisterType<MyObject>("MyObj",1,0,"MyObject"); //通过模板创建
//通过单例创建
// qmlRegisterSingletoInstance("MyObj",1,0,"MyObject",MyObject::getInst() );//没有这个方法qt15引入。
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);
//engine加载完成之后
auto list = engine.rootObjects(); //返回的是main.qml QML文件的所有对象。
//第一个元素的windows
QObject* window = list.first();
QObject* btn = list.first()->findChild<QObject*>("mybtn");
qDebug()<< window <<"|"<< window->objectName();
qDebug()<< btn <<"|"<< btn->objectName();
// 方式三
QObject::connect(window,SIGNAL(qmlSig(int,QString) ),MyObject::getInst(),SLOT(cppSlot(int,QString)) );
QObject::connect(MyObject::getInst(),SIGNAL(cppSig(QVariant,QVariant) ),window,SLOT(qmlSlot(QVariant,QVariant) ) );
return app.exec();
}
main.qml
css
import QtQuick 2.12
import QtQuick.Window 2.12
import QtQuick.Controls 2.12
import MyObj 1.0
Window {
id:window
visible: true
width:600
height: 400
objectName: "mywindow"
title: qsTr("QML与C++交互")
signal qmlSig(int i,string s)
MyObject{ //C++中的对象。
id:myobj
iValue: 1
m_sString: "m_sString_test"
}
Button{
objectName: "mybtn"
onClicked: {
console.log("click")
myobj.fun() //MyObject.fun()
}
}
function qmlSlot(i,s){ // 参数类型 对应cpp端 都是QVariant
console.log(i,s);
}
Connections{
target: myobj
onCppSig:{
console.log(i,s);
}
// function onCppSig(i,s){
// qmlSlot(i,s)
// }
}
}