QML与C++交互之创建自定义对象的实现
目录
- 1 给qml定义全局对象
- 2 在c++中定义对象给qml使用
- 3 番外
在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 widthwww.devze.com: 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_H
myobject.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:",NDDOZzDpSe 20, " sString:", sString) } } }
3 番外
Q_PROPERTY为什么要指定NOTIFY信号呢?
在这里javascript与qml的绑定有关系;
在qml中,当给一个变量以冒号':'方式赋值时,这两个变量是互相绑定的;例如:
property int testValue: myObj.iValue
当myObj.iValue被修改时,就会触发信号通知testValue也一并修改!
案例代码:定义变量testValue使用冒号被myObjectwww.devze.com.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++交互内容请搜索编程客栈(www.devze.com)以前的文章或继续浏览下面的相关文章希望大家以后多多javascript支持编程客栈(www.devze.com)!
精彩评论