一、 qmlRegisterType()
- 使用元对象系统将C++类暴露,通常使用Q_OBJECT宏注册从QObject派生的类,也可以用Q_GADGET宏声明一个比QObject“更轻”的版本。
-
Q_PROPERTY注册属性
-
Q_ENUMS声明枚举
-
Q_INVOKABLE标记public函数
#ifndef BACKEND_H #define BACKEND_H #include <QObject> #include <QString> class BackEnd : public QObject { Q_OBJECT Q_PROPERTY(QString userName READ userName WRITE setUserName NOTIFY userNameChanged) public: explicit BackEnd(QObject *parent = nullptr); QString userName(); void setUserName(const QString &userName); signals: void userNameChanged(); private: QString m_userName; }; #endif // BACKEND_H #include "backend.h" BackEnd::BackEnd(QObject *parent) : QObject(parent) { } QString BackEnd::userName() { return m_userName; } void BackEnd::setUserName(const QString &userName) { if (userName == m_userName) return; m_userName = userName; emit userNameChanged(); }
-
qmlRegisterType注册到QML中
#include
#include#include “backend.h”
int main(int argc, char *argv[])
{
QGuiApplication app(argc, argv);qmlRegisterType<BackEnd>("io.qt.examples.backend", 1, 0, "BackEnd"); QQmlApplicationEngine engine; engine.load(QUrl(QStringLiteral("qrc:/main.qml"))); return app.exec();
}
-
在QML中使用
import QtQuick 2.6
import QtQuick.Controls 2.0
import io.qt.examples.backend 1.0ApplicationWindow {
id: root
width: 300
height: 480
visible: trueBackEnd { id: backend } TextField { text: backend.userName placeholderText: qsTr("User name") anchors.centerIn: parent onTextChanged: backend.userName = text }
}
二、注册非实例化类型
- qmlRegisterInterface()使用特定的QML类型名称注册Qt的接口类型。类型不能从QML实例化,但可以通过其类型名引用。
- qmlRegisterUncreatableType()注册一个C++类型,该类型不可实例化,但应可识别为QML类型系统的类型。如果类型的枚举或附加属性应该可以从QML访问,但是类型本身不应该是可实例化的,那么这很有用。
- qmlRegisterSingletonType() 注册可以从QML导入的单例类型。
单例类型
假设我们有一个用于主题的单例类型,它已注册到MyThemeModule1.0版本的名称空间中,其中QObject具有一个QColor color属性。然后我们可以简单地使用它:
import MyThemeModule 1.0 as Theme
Rectangle {
color: Theme.color // binding.
}
三、 C++调用QML
-
在QML中我定义了一些属性和方法等,用于测试。
import QtQuick 2.9 Item{ id: root width: 250 height: 250 //自定义属性 --cpp可以访问 property string msg: "GongJianBo1992" //自定义信号 --可以触发cpp槽函数 signal qmlSendMsg(string arg1,string arg2) Rectangle { anchors.fill: parent color: "green" objectName: "rect" //用于cpp查找对象 } MouseArea { anchors.fill: parent onClicked: { console.log("qml 点击鼠标, 发送信号 qmlSendMsg") root.qmlSendMsg(root.msg,"myarg2") } } onHeightChanged: console.log("qml height changed") onWidthChanged: console.log("qml width changed") //QML中的方法可以被cpp调用,也可以作为槽函数 function qml_method(val_arg){ console.log("qml method runing",val_arg,"return ok") return "ok" } //注意槽函数参数为var类型 function qmlRecvMsg(arg1,arg2){ console.log("qml slot runing",arg1,arg2) } } #ifndef CPPOBJECT_H #define CPPOBJECT_H #include <QObject> #include <QDebug> class CppObject : public QObject { Q_OBJECT public: explicit CppObject(QObject *parent = Q_NULLPTR) :QObject(parent){} signals: //信号 --用来触发qml的函数 //注意参数为var类型,对应qml中js函数的参数类型 void cppSendMsg(const QVariant &arg1,const QVariant &arg2); public slots: //槽函数 --用来接收qml的信号 void cppRecvMsg(const QString &arg1,const QString &arg2){ qDebug()<<"CppObject::cppRecvMsg"<<arg1<<arg2; qDebug()<<"emit cppSendMsg"; emit cppSendMsg(arg1,arg2); } };
-
Cpp中定义了一个槽函数,用来接收QML对象的信号。
#include <QGuiApplication> #include <QQmlProperty> #include <QQuickView> #include <QQuickItem> #include <QMetaObject> #include <QDebug> #include "CppObject.h" int main(int argc, char *argv[]) { QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling); QGuiApplication app(argc, argv); //可以用QQmlComponent\QQuickView\QQuickWidget的C++代码加载QML文档 //QQuickView不能用Window做根元素 QQuickView view(QUrl("qrc:/main.qml")); view.show(); //获取到qml根对象的指针 QObject *qmlObj=view.rootObject(); /*文档如是说: 应该始终使用QObject::setProperty()、QQmlProperty 或QMetaProperty::write()来改变QML的属性值,以确保QML引擎感知属性的变化。*/ //【1】 //通过QObject设置属性值 qDebug()<<"Cpp set qml property height"; //qmlObj->setProperty("height",300); QQmlProperty(qmlObj,"height").write(300); //通过QObject获取属性值 qDebug()<<"Cpp get qml property height"<<qmlObj->property("height"); //任何属性都可以通过C++访问 qDebug()<<"Cpp get qml property msg"<<qmlObj->property("msg"); //【2】 QQuickItem *item=qobject_cast<QQuickItem*>(qmlObj); //通过QQuickItem设置属性值 qDebug()<<"Cpp set qml property width"; item->setWidth(300); //通过QQuickItem获取属性值 qDebug()<<"Cpp get qml property width"<<item->width(); //【3】 //通过objectName访问加载的QML对象 //QObject::findChildren()可用于查找具有匹配objectName属性的子项 QObject *qmlRect=qmlObj->findChild<QObject*>("rect"); if(qmlRect){ qDebug()<<"Cpp get rect color"<<qmlRect->property("color"); } //【4】 //调用QML方法 QVariant val_return; //返回值 QVariant val_arg="GongJianBo"; //参数值 //Q_RETURN_ARG()和Q_Arg()参数必须制定为QVariant类型 QMetaObject::invokeMethod(qmlObj, "qml_method", Q_RETURN_ARG(QVariant,val_return), Q_ARG(QVariant,val_arg)); qDebug()<<"QMetaObject::invokeMethod result"<<val_return; //qml函数中返回“ok” //【5】 //关联信号槽 CppObject cppObj; //关联qml信号与cpp槽 //如果信号参数为QML对象类型,信号用var参数类型,槽用QVariant类型接收 QObject::connect(qmlObj,SIGNAL(qmlSendMsg(QString,QString)), &cppObj,SLOT(cppRecvMsg(QString,QString))); //关联cpp信号与qml槽 //qml中js函数参数为var类型,信号也用QVariant类型 QObject::connect(&cppObj,SIGNAL(cppSendMsg(QVariant,QVariant)), qmlObj,SLOT(qmlRecvMsg(QVariant,QVariant))); //此外,cpp信号也可以关联qml信号 return app.exec(); }