简述: QML与C++混合编程就是使用QML高效便捷地构建UI,而C++则用来实现业务逻辑和复杂算法。 1> Qt集成了QML引擎和Qt元对象系统,使得QML很容易从C++中得到扩展,在一定的条件下,QML就可以访问QObject派生类的成员,例如信号、槽函数、枚举类型、属性、成员函数等。 QML访问C++有两个方法: 2> 在C++中也可以访问QML中的属性、函数和信号。 在C++中加载QML文件可以用QQmlComponent或QQuickView,然后就可以在C++中访问QML对象。QQuickView提供了一个显示用户界面的窗口,而QQmlComponent没有。 3> 几个重要的类: 系统:Qt 5 + linux 一个C++类要想被QML访问,必须满足两个条件: 这和使用信号与槽的前提条件是一样的。QObject类是所有Qt对象的基类,作为Qt对象模型的核心,提供了信号与槽机制等很多重要特性。这两个条件是为了让一个类能够进入 Qt 强大的元对象系统(meta-object system)中,而使用元对象系统,一个类的某些方法或属性才可能通过字符串形式的名字来调用。 实现一个可被QML访问的类,可以访问类中的信号、槽函数、枚举类型、属性、成员函数等。 1> 几个重要的宏: 2> Q_PROPERTY宏原型: 3> 信号和槽 被QML访问的槽必须声明为public或protected。信号在C++中使用时要用到emit关键字,但在QML中就是个普通的函数,用法同函数一样,信号处理器形式为on,Signal首字母大写。信号不支持重载,多个信号的名字相同而参数不同时,能够被识别的只是最后一个信号,与信号的参数无关。 4> C++ 类的实现 注册一个C++类,并被QML访问,步骤如下表 1> QObject派生类可以注册到Qt元对象系统,使得类在QML中同其它内建类型一样,可以作为一个数据类型来使用。QML引擎允许注册可实例化的类型,也可以是不可实例化的类型,常见的注册函数有: template<typename T>int qmlRegisterType(const char *uri,int versionMajor, int versionMinor, const char *qmlName); 例如, 语句 “import QtQuick.Controls 1.1″中, “QtQuick.Controls” 就是包名 uri ,而 1.1 则是版本号,是 versionMajor 和 versionMinor 的组合。 main.cpp中将Login类注册为在QML中可以使用的Login类型,主版本为1,次版本为0,库的名字是Login.module。main.qml中导入了C++库,使用Login构造了一个对象,id为login,可以借助id来访问C++。 注册动作必须在QML上下文创建前,否则无效。 2> 在QML中导入C++注册的类型 import Login.module 1.0 3> 在QML文件中导入C++类并使用 在QML中访问C++的成员函数的形式是“.”,如login.show(),支持函数重载。 C++类中的m_color属性可以在QML中访问、修改,访问时调用了color()函数,修改时调用setColor()函数,同时还发送了一个信号来自动更新color属性值。 设置QML上下文属性,并被QML访问,步骤如下表 1> C++设置QML上下文属性 Login类先实例化为login对象,然后注册为QML上下文属性 engine.rootContext()、viewer.rootContext() 返回的是 QQmlContext 对象。 QQmlContext 类代表一个 QML 上下文,它的 setContextProperty() 方法能够为该上下文设置一个全局可见的属性。 2 > QML 使用 没有使用 qmlRegisterType()来注册Login类,则qml 中不能再訪问 Login 类,所以不能通过类名来引用它定义的枚举类型,即Login中的枚举类型在QML中是访问不到的。而属性,成员函数,信号和槽均可以访问。 在C++中也可以访问QML中的属性、函数和信号。 1> 加载QML文件 在C++中加载QML文件可以用QQmlComponent或QQuickView,然后就可以在C++中访问QML对象。QQuickView提供了一个显示用户界面的窗口,而QQmlComponent没有。 2> 访问QML属性 QObject::property()/setProperty()来读取、修改width属性值。 QQmlProperty::read()/write()来读取、修改height属性值。 如果某个对象的类型是QQuickItem,例如QQuickView::rootObject()的返回值,可以使用QQuickItem::width/setWidth()来访问、修改width属性值。 3>查找组件 QML组件是一个复杂的树型结构,包含兄弟组件和孩子组件,可以使用QObject::findChild()/findChildren()来查找。 4> 访问QML函数 在C++中,使用QMetaObject::invokeMethod()可以调用QML中的函数,从QML传递过来的函数参数和返回值会被转换为C++中的QVariant类型,成功返回true,参数不正确或被调用函数名错误返回false.。 第一个invokeMethod()参数说明: 必须使用Q_ARG()宏来声明函数参数,用Q_RETURN_ARG()宏来声明函数返回值,其原型如下: 5> C++中使用QML的信号 使用QObject::connect()可以连接QML中的信号,connect()共有四个重载函数,都是静态函数。必须使用SIGNAL()宏来声明信号,SLOT()宏声明槽函数。 使用QObject::disconnect()可以解除信号与槽函数的连接。 QML中添加了一个Rectangle,设置objectName属性值为“rect”,objectName是为了在C++中能够找到Rectangle。 QML中添加了qmlSignal()信号和qmlFunction()函数,信号在QML中发送,函数在C++中调用。
序号
方法
备注
1
在Qt元对象系统中注册C++类,在QML中实例化、访问
可以使C++类在QML中作为一个数据类型
2
在C++中实例化并设置为QML上下文属性,在QML中直接使用
序号
类
作用
备注
1
QDeclarativeEngine
提供了QML的运行环境
2
QDeclarativeContext
允许程序使用QML组件显示数据
3
QDeclarativeComponent
封装了QML Documents
4
QDeclarativeView
用于在应用程序开发过程中进行快速原型开发
方便的把QML组件嵌入到QGraphicsView中
1、QML访问C++
序号
条件
1
从QObject类或QObject类的子类派生继承
2
使用Q_OBJECT宏
1.1 C++类的实现
序号
宏
描述
备注
1
Q_INVOKABLE
可使QML中访问C++public或protected成员函数
函数返回类型的前面
2
Q_ENUMS
Q_ENUMS 宏将枚举类型注冊到元对象系统中,便可被QML访问
QML中使用枚举类型的方式是通过C++类型名使用“.”操作符直接访问枚举成员
3
Q_PROPERTY
用来定义可通过元对象系统訪问的属性
能够在 QML 中訪问、改动,也能够在属性变化时发射特定的信号
Q_PROPERTY( type name READ getFunction [WRITE setFunction] [RESET resetFunction] [NOTIFY notifySignal] [REVISION int] [DESIGNABLE bool] [SCRIPTABLE bool] [STORED bool] [USER bool] [CONSTANT] [FINAL] )
序号
项目
描述
备注
1
name
属性名,类型可以QVariant支持的任何类型,也可以是自定义类型
必选
2
READ
读取属性值,返回值必须为属性类型或者属性类型的引用或者指针
必选
3
WRITE
设置属性值,返回值必须为void型,带参数,参数类型必须是属性本身的类型或类型的指针或引用
可选
4
RESET
重设属性为默认状态,返回值必须为void型,且不带参数
可选
5
NOTIFY
提供了一个信号,这个信号在值发生改变时会自动被触发
可选
6
REVISION
可选
7
DESIGNABLE
表明该属性能在GUI builder(一般为Qt Designer)可见
可选
8
SCRIPTABLE
表明这个属性是否可以被一个脚本引擎操作(默认是true)
可选
9
STORED
表明这是一直存在的
可选
10
USER
定义是否可以被用户所编辑
可选
11
CONSTANT
定义属性是不可修改的,所以不能跟WRITE或者NOTIFY同时出现
可选
12
FINAL
表明该属性不会被派生类中重写
可选
#ifndef LOGIN_H #define LOGIN_H #include <QObject> #include <QDebug> #define GAME "GAME" class Login: public QObject { Q_OBJECT //枚举类型注册 Q_ENUMS(Color) //属性声明 Q_PROPERTY(Color color READ getColor WRITE setColor NOTIFY colorChanged) Q_PROPERTY(QString deviceId READ getDeviceId WRITE setDeviceId) Q_PROPERTY(QString password READ getPassword WRITE setPassword) public: Login(QObject *parent) : QObject(parent){ qDebug() << "Welcome.";} //枚举 enum Color { RED, BLUE, BLACK }; //成员函数 Q_INVOKABLE void show(){ qDebug() << "show() is called."; } Q_INVOKABLE void login(){ qDebug() << "login() is called."; } Color getColor() const{return m_color;} void setColor(const Color& color){m_color = color;emit colorChanged();} QString getDeviceId() {return deviceId;} void setDeviceId(QString id) {deviceId = id;} QString getPassword() {return password;} void setPassword(QString pw) {password = pw;} public slots: void doSomething(Color color) { qDebug() << "dosomething() is called " << color; } signals: void begin(); void colorChanged(); private: Color m_color;//属性 QString deviceId; QString password; }; #endif // LOGIN_H
1.2 注册C++类
序号
步骤
1
实现一个C++类,请参考 1.1
2
将该类注册为QML类型
3
在QML导入类型
4
在 QML 创建由 C++ 导出的类型的实例并使用
注册函数
描述
qmlRegisterInterface()
qmlRegisterRevision()
qmlRegisterSingletonType()
注冊一个单例类型
qmlRegisterType()
注冊一个非单例的类型
qmlRegisterTypeNotAvailable()
注冊一个类型用来占位
qmlRegisterUncreatableType()
注冊一个具有附加属性的附加类型
模板函数注册C++类到Qt元对象系统中,参数说明如下:
参数
说明
uri
需要导入到QML中的库/包名
versionMajor
主版本号
versionMinor
次版本号
qmlName
在QML中可以使用的类名
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "login.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QGuiApplication app(argc, argv); //注册C++类型Login qmlRegisterType<Login>("Login.module",1,0,"Login"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
import QtQuick 2.9 import QtQuick.Window 2.2 //导入注册的C++类 import Login.module 1.0 Window { id:root visible: true width: 1920 height: 1080 title: qsTr("Login QML") property string tips: "" property int count: 0 property var array: [ "qrc:/Res/sound1.wav", "qrc:/Res/sound2.wav", "qrc:/Res/sound3.wav" ] signal finished() Component.onCompleted: { console.log("Hello,Hello") } MouseArea { anchors.fill: parent onClicked: { //单击鼠标调用begin信号函数 login.begin() login.show() //修改属性 login.color = 2 login.password = "123456" login.deviceId = "admin" } } Login{ id:login //Login类的实例 onBegin: { doSomething(Login.RED) } onColorChanged: { console.log("color changed.") } } }
1.3 QML上下文属性设置
序号
步骤
1
实现一个C++类,请参考 1.1
2
C++设置QML上下文属性
3
在QML中使用
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "login.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QGuiApplication app(argc, argv); QQmlApplicationEngine engine; Login login; engine.rootContext()->setContextProperty("login", &login); engine.rootContext()->setContextProperty("GAME", GAME); engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec(); }
#include <QGuiApplication> #include <QQuickView> #include <QQmlContext> #include "login.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QGuiApplication app(argc, argv); QQuickView view; Login login; view.rootContext()->setContextProperty("login", &login); view.rootContext()->setContextProperty("GAME", GAME); view.setSource(QUrl(QStringLiteral("qrc:/main.qml"))); view.show(); return app.exec(); }
import QtQuick 2.9 import QtQuick.Window 2.2 Window { id:root visible: true width: 1920 height: 1080 title: qsTr("Login QML") property string tips: "" property int count: 0 property var array: [ "qrc:/Res/sound1.wav", "qrc:/Res/sound2.wav", "qrc:/Res/sound3.wav" ] signal finished() Component.onCompleted: { console.log("Hello,Hello") } MouseArea { anchors.fill: parent onClicked: { //单击鼠标调用begin信号函数 login.begin() login.show() //修改属性 login.color = 2 login.password = 123456 login.deviceId = admin } } Connections{ target:login onBegin: { console.log("begin.") console.log(GAME) } onColorChanged: { console.log("color changed.") } } }
2、C++访问QML
2.1 C++访问QML的知识要点
方法
描述
findChild
返回单个对象
findChildren
返回对象列表
//查找 parentWidget 的名为 "button1" 的类型为 QPushButton 的孩子: QPushButton *button = parentWidget->findChild<QPushButton *>("button1"); //查找 parentWidget 全部名为 "widgetname" 的 QWidget 类型的孩子列表 QList<QWidget *> widgets = parentWidget.findChildren<QWidget *>("widgetname");
static bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()); static inline bool invokeMethod(QObject *obj, const char *member, QGenericReturnArgument ret, QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) { return invokeMethod(obj, member, Qt::AutoConnection, ret, val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } static inline bool invokeMethod(QObject *obj, const char *member, Qt::ConnectionType type, QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) { return invokeMethod(obj, member, type, QGenericReturnArgument(), val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); } static inline bool invokeMethod(QObject *obj, const char *member, QGenericArgument val0 = QGenericArgument(Q_NULLPTR), QGenericArgument val1 = QGenericArgument(), QGenericArgument val2 = QGenericArgument(), QGenericArgument val3 = QGenericArgument(), QGenericArgument val4 = QGenericArgument(), QGenericArgument val5 = QGenericArgument(), QGenericArgument val6 = QGenericArgument(), QGenericArgument val7 = QGenericArgument(), QGenericArgument val8 = QGenericArgument(), QGenericArgument val9 = QGenericArgument()) { return invokeMethod(obj, member, Qt::AutoConnection, QGenericReturnArgument(), val0, val1, val2, val3, val4, val5, val6, val7, val8, val9); }
参数
说明
备注
第一个参数
被调用对象的指针
第二个参数
访问的函数名
第三个参数
连接类型
第四个参数
用来接收返回值
其他参数
传递被调用方法的参数
不能超过10个
QGenericArgument Q_ARG(Type, const Type & value) QGenericReturnArgument Q_RETURN_ARG(Type, Type & value)
2.2 QML中定义信号、函数、元素属性
import QtQuick 2.9 import QtQuick.Window 2.2 //导入注册的C++类 import Login.module 1.0 Window { id:root visible: true width: 1920 height: 1080 color: "white" title: qsTr("Login QML") property string tips: "" property int count: 0 property var array: [ "qrc:/Res/sound1.wav", "qrc:/Res/sound2.wav", "qrc:/Res/sound3.wav" ] signal finished() //定义信号 signal qmlSigStart(string message) Component.onCompleted: { console.log("Hello,Hello") } MouseArea { anchors.fill: parent onClicked: { //单击鼠标调用begin信号函数 login.begin() login.show() //修改属性 login.color = 2 login.password = "123456" login.deviceId = "admin" //发送信号 qmlSigStart("This is an qml signal.") } } Rectangle{ //设置objectName属性值为“rect”,objectName是为了在C++中能够找到Rectangle objectName: "rect" anchors.fill: parent color:"red" } Login{ id:login //Login类的实例 onBegin: { doSomething(Login.RED) } onColorChanged: { console.log("color changed.") } } //定义函数 function qmlFunction(parameter) { console.log("qml function parameter is", parameter) return "function from qml" } }
2.3 C++ 中访问QML代码示例
#include <QGuiApplication> #include <QQmlApplicationEngine> #include <QtQml> #include "login.h" int main(int argc, char *argv[]) { qputenv("QT_IM_MODULE", QByteArray("qtvirtualkeyboard")); QGuiApplication app(argc, argv); //注册C++类型Login qmlRegisterType<Login>("Login.module",1,0,"Login"); QQmlApplicationEngine engine; QQmlComponent component(&engine, QUrl(QStringLiteral("qrc:/main.qml"))); QObject* object = component.create(); qDebug() << "width value is" << object->property("width").toInt(); object->setProperty("width", 1280);//设置window的宽 qDebug() << "width value is" << object->property("width").toInt(); qDebug() << "height value is" << QQmlProperty::read(object, "height").toInt(); QQmlProperty::write(object, "height", 720);//设置window的高 qDebug() << "height value is" << QQmlProperty::read(object, "height").toInt(); QObject* rect = object->findChild<QObject*>("rect");//查找名称为“rect”的元素 if(rect) { rect->setProperty("color", "blue");//设置元素的color属性值 qDebug() << "color is " << object->property("color").toString(); } //调用QML中函数 QVariant returnedValue; QVariant message = "Login from C++"; QMetaObject::invokeMethod(object, "qmlFunction", Q_RETURN_ARG(QVariant, returnedValue), Q_ARG(QVariant, message)); qDebug() << "returnedValue is" << returnedValue.toString(); // function from qml Login login; //连接QML元素中的信号到C++ Login类的槽函数slotStart QObject::connect(object, SIGNAL(qmlSigStart(QString)), &login, SLOT(slotStart(QString))); return app.exec(); }
3、QML嵌入到QWidget中方法
本网页所有视频内容由 imoviebox边看边下-网页视频下载, iurlBox网页地址收藏管理器 下载并得到。
ImovieBox网页视频下载器 下载地址: ImovieBox网页视频下载器-最新版本下载
本文章由: imapbox邮箱云存储,邮箱网盘,ImageBox 图片批量下载器,网页图片批量下载专家,网页图片批量下载器,获取到文章图片,imoviebox网页视频批量下载器,下载视频内容,为您提供.
阅读和此文章类似的: 全球云计算