QML之混合编程:注册类(二)

一、 qmlRegisterType()

  1. 使用元对象系统将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();
        }
    
  1. 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();
    

    }

  2. 在QML中使用

    import QtQuick 2.6
    import QtQuick.Controls 2.0
    import io.qt.examples.backend 1.0

    ApplicationWindow {
    id: root
    width: 300
    height: 480
    visible: true

       BackEnd {
           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

  1. 在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);
         }
     };
    
  2. 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();
     }
    
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值