本帖内容主要记录qml前端界面与c++后端之间的通信方式。
1、在c++源程序中定义内容,提供给qml界面端访问。
#include<QQmlContext>//需要的头文件
QGuiApplication app(argc, argv);
QQmlApplicationEngine engine;
QQmlContext* context = engine.rootContext();
//auto context = engine.rootContext();//用这两种表述都可以,auto自动推断类型
context->setContextProperty("myset",120);
在main.cc文件中添加上述代码后,即可在qml文件直接使用myset来使用。比如赋值给窗口的宽度。
ApplicationWindow {
width: myset
height: 400
visible: true
title: qsTr("Hello World")
}
按上述设置后即可在所有的qml文件中使用myset。这种方法的弊端是使用上下文注册的类型都是作用于全局的,这种做法可能会带来性能的影响,同时,在各个文件中可能出现重复的名称,如int myset = 1000,那么则会直接使用本地的数据。
所以,一般我们需要设置一个全局需要访问的值的时候才需要使用注册上下文的方式,更多的是使用如下方式。
2、使用qmlRegisterType来将该类型注册到qml文件中使用
我们首先在qt项目中添加一个c++类,如下所示:
选择c++ class,然后类一定要继承自QObiect,然后选中需要的项即可。
新生成的MyObj123的类的内容如下:
这里面选择了添加Q_OBJECT和QML_ELEMENT,如何上一步没有选择,可以自己添加。这里的Q_OBJECT主要是为了使用信号与槽的特性,而QML_ELEMENT则是为了声明这个类可以在qml界面文件中使用,如果缺失QML_ELEMENT会造成qml中import不了该类型。
在主程序main.cc中使用qmlRegisterType来将定义的类型注册到qml中去。代码如下:
#include "myobj.h" //在主程序中需要引入我们定义类型的头文件
qmlRegisterType<MyObj>("com.mycompany.Myobj",1,0,"MyObj123");
其中qmlRegisterType<MyObj>("com.mycompany.Myobj",1,0,"MyObj123");中的<MyObj>是我们需要注册的类型。com.mycompany.Myobj是我们在qml文件中使用import引入模块的模块名,后面两个是主版本和次版本号。MyObj123是我们在qml中可以直接使用的类名称。
在qml文件中的使用代码如下:
import QtQuick
import QtQuick.Window
import QtQuick.Controls
import com.mycompany.Myobj
ApplicationWindow {
width: 500
height: 400
visible: true
title: qsTr("Hello World")
MyObj123{//直接使用前面注册的类名称
id:myobj1
mydata: 40
onMydataChanged: {
console.log(mydata)
}
Component.onCompleted:{
console.log(mydata)
}
}
Button{
width: 60
height: 60
onClicked: {
myobj1.mydata = 50
console.log(myobj1.mydata)
}
}
}
这样就可以在qml中访问c++定义类型的数据了。但是,如何访问该类型的方法呢?
如果直接使用id名.方法,即myobj1.fun(),运行程序会报错,说找不到方法对象。
其实解决这个问题非常简单,即在方法前面加上Q_INVOKABLE即可,如下:
Q_INVOKABLE void fun();
//Q_INVOKABLE宏是用来标记一个函数,使其能够被Qt元对象系统(Meta-Object System)识别,并且可以被QML调用。这通常用于C++类中定义的函数,使得这些函数可以在QML代码中被访问和调用。
并在qml文件中直接调用即可。