在qml中,我们一般都是希望使用qml做界面展示,而数据处理转由c++处理;
在此篇博客,将介绍如何在c++中给qml定义全局对象;在c++中如何定义对象给qml使用。
1 给qml定义全局对象
正常我们定义了一个qml项目后,main函数是这样的:
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
int main(int argc, char *argv[])
{
qcoreapplication::setattribute(qt::aa_enablehighdpiscaling);
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
return app.exec();
}qqmlapplicationengine 是 qt 框架中用于加载和运行基于 qml 的应用程序的核心类,结合了 qqmlengine 和 qqmlcomponent 的功能,支持从单个 qml 文件加载应用程序,并实现 c++ 与 qml 的双向通信。
那么,就可以使用qqmlapplicationengine去获得全局上下文对象qqmlcontext,通过使用上下文对象,就可以给qml设置一个全局的变量值;
获得上下文对象:
// 获得全局对象,上下文对象 qqmlcontext *context = engine.rootcontext();
给qml设置一个全局变量:
// 给qml设置一个全局变量;
context->setcontextproperty("screen_width", 800);这样,就可以在qml中使用该变量了,例如在mian.qml文件内使用:
import qtquick 2.9
import qtquick.window 2.2
import qtquick.controls 2.14
window {
id: root
visible: true
width: screen_width // 直接使用
height: 500
title: qstr("hello world")
color: "white"
// 如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量,而不会使用c++定义的变量
//property int screen_width: 500
}
注意:如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能消耗问题。
2 在c++中定义对象给qml使用
自定义c++类myobject继承自qobject;有两个成员变量,int m_ivalue 和 qstring m_sstring;并且给他俩定义get和set方法;另外在定义两个信号;最后通过q_property将两个成员变量暴露给元对象。
myobject.h
#ifndef myobject_h
#define myobject_h
#include <qobject>
class myobject : public qobject
{
q_object
public:
myobject(qobject *parent = nullptr); // 构造函数
~myobject();
const int &ivalue() const;
void setiivalue(const int &newivalue);
const qstring &sstring() const;
void setsstring(const qstring &newsstring);
signals:
void ivaluechanged();
void sstringchanged();
private:
int m_ivalue;
qstring m_sstring;
q_property(int ivalue read ivalue write setiivalue notify ivaluechanged)
// q_property(qstring sstring read sstring write setsstring notify sstringchanged)
// 如果值是函数内部成员变量的值,可使用member去设置,与read sstring write setsstring实现效果一致
q_property(qstring sstring member m_sstring notify sstringchanged)
};
#endif // myobject_hmyobject.cpp
#include "myobject.h"
myobject::myobject(qobject *parent) : qobject(parent)
{
}
myobject::~myobject()
{
}
const int &myobject::ivalue() const
{
return m_ivalue;
}
void myobject::setiivalue(const int &newivalue)
{
if (m_ivalue == newivalue) {
return;
}
m_ivalue = newivalue;
emit ivaluechanged();
}
const qstring &myobject::sstring() const
{
return m_sstring;
}
void myobject::setsstring(const qstring &newsstring)
{
if (m_sstring == newsstring) {
return;
}
m_sstring = newsstring;
emit sstringchanged();
}q_property的参数讲解
q_property(int ivalue read ivalue write setiivalue notify ivaluechanged)
int ivalue 指定是给qml使用的变量名,推荐与c++类成员变量名类似;
read ivalue 指的是通过ivalue函数去读取值;
write setiivalue 指的是通过setiivalue函数去修改ivalue值;
notify ivaluechanged 指的是当ivalue值被修改后,会发送的信号;
然后main函数中使用qmlregistertype函数对自定义类进行注册,注册后,就可以在qml那边导入使用了。
#include <qguiapplication>
#include <qqmlapplicationengine>
#include <qqmlcontext>
#include "myobject.h"
int main(int argc, char *argv[])
{
qcoreapplication::setattribute(qt::aa_enablehighdpiscaling);
qguiapplication app(argc, argv);
qqmlapplicationengine engine;
// 获得全局对象,上下文对象
qqmlcontext *context = engine.rootcontext();
// 给qml设置一个全局变量;如果qml内部有定义重名变量,那么会优先使用qml内部定义的变量;另外,定义全局变量会有性能问题
context->setcontextproperty("screen_width", 800);
// 注册,在需要使用的地方 import myobj 1.0
qmlregistertype<myobject>("myobj", 1, 0, "myobject");
engine.load(qurl(qstringliteral("qrc:/main.qml")));
if (engine.rootobjects().isempty())
return -1;
return app.exec();
}其中,myobj是给qml那边导入时使用的模块名字,1 和 0 指的是版本,最后的myobject就是自定义类名;
然后就可以在qml中 import myobj 1.0 导入使用了。
import qtquick 2.9
import qtquick.window 2.2
import qtquick.controls 2.14
import myobj 1.0 // 导入自定义模块
window {
id: root
visible: true
width: screen_width
height: 500
title: qstr("hello world")
color: "white"
myobject {
ivalue: 20
sstring: "this is a custom obj.";
component.oncompleted: {
console.log("ivalue:", 20, " sstring:", sstring)
}
}
}
3 番外
q_property为什么要指定notify信号呢?
在这里与qml的绑定有关系;
在qml中,当给一个变量以冒号':'方式赋值时,这两个变量是互相绑定的;例如:
property int testvalue: myobj.ivalue
当myobj.ivalue被修改时,就会触发信号通知testvalue也一并修改!
案例代码:定义变量testvalue使用冒号被myobject.ivalue赋值,定义按钮在onclicked槽函数中修改myobj.ivalue值,观察testvalue是否也被修改;
import qtquick 2.9
import qtquick.window 2.2
import qtquick.controls 2.14
import myobj 1.0 // 导入自定义模块
window {
id: root
visible: true
width: screen_width
height: 500
title: qstr("hello world")
color: "white"
property int testvalue: myobj.ivalue // 绑定了
ontestvaluechanged: {
console.log("testvalue:", testvalue)
}
button {
width: 100; height: 50
onclicked: {
myobj.ivalue = 50;
}
}
myobject {
id: myobj
ivalue: 20
sstring: "this is a custom obj.";
component.oncompleted: {
console.log("ivalue:", 20, " sstring:", sstring)
}
}
}当点击按钮后,修改的是myobj.ivalue,但testvalue也一并被修改了,由此证明,使用冒号赋值时,他俩是会绑定在一起的。

注意,使用 = 赋值时,不会有绑定的效果!!!
到此这篇关于qml与c++交互之创建自定义对象的实现的文章就介绍到这了,更多相关qml与c++交互内容请搜索代码网以前的文章或继续浏览下面的相关文章希望大家以后多多支持代码网!
发表评论