QML与C++集成<二>——<使用C++属性及注册QML类型>

前言

  在开始讲之前首先讲一个使用属性(setContextProperty)注册类型(qmlRegisterType)的区别,在这主要讲一些我个人工作中的情况,其实二者都是将c++类暴露给QML的方法,只不过在使用时存在一些区别,根据使用方式不同我个人分为C++的形式和QML的定义形式。

1、C++定义方式(主要使用setContextProperty()函数)

  • a)、比如我们有一个功能单一的Configure类,我们需要把它暴露给QML,在使用之前必须要先创建类对象m_configuration,就是说类实例化一次,QML中可以直接使用这个类,注意功能单一的类只适合该方式;
  • b)、比如我们的业务比较复杂,我们有很多类,若要供QML调用,我们就要写一个总的被调用类Complex(包含所有的业务类),然后实例化一次这个Complex,然后QML中直接使用实例化后的对象;

两种业务方式的使用方式如下:

QQuickView viewer;
viewer.rootContext()->setContextProperty("_configuration",&m_configuration);

_configuration便可直接在qml中使用,_configuration自然也是一个全局变量。

2、QML的方式,(主要使用qmlRegisterType()函数)

  该方式都是使用在业务复杂情况下,还是上面的例子,我们有一堆业务类,这个时候我们使用注册的方式,用在QML中定义的方式去定义各个实例,也就不用再需要一个总类:

qmlRegisterType<Foo>("App", 1, 0, "Foo");
qmlRegisterType<Bar>("Bar", 1, 0, "Bar");//注册不可实例化的类型

我们可以再QML中直接使用Foo去定义实例:

import App 1.0

Foo {
      bar.baz: "abc"
      Component.onCompleted: print(bar.baz)
  }

3、二者比较

  与C++方式相比,QML具有如下优势:

  • 变量名前面可以加$(全局变量可用),从而方便区分全局变量和局部变量,这个在C++定义属性的时候是不允许的;

  • 如果某个全局变量(一般是QML对象)构造很慢,可以通过QML中的Loader来很方便异步构造,从而加速程序启动:

一、在QML中使用C++属性

  QObject子类的所有属性都能够被QML访问,QObject子类使用Q_PROPERTY宏定义一个属性,该宏的作用是向Qt元对象系统注册类的属性,一个类的属性就是类的数据成员,通常会有一个用于读取的READ函数和一个可选的用于修改的WRITE函数。

该宏定义如下:

 一些常见的申明示例:

使用我们一般使用setContextProperty()函数,注意和注册的区别,使用一版如下,m_configuration就是一个全局变量,便可在qml中直接使用

QQuickView viewer;
viewer.rootContext()->setContextProperty("_configuration",&m_configuration);

 1.1 使用函数和槽

  QML可以有条件地访问QObject子类的函数:

  • 使用Q_INVOKABLE宏标记的public函数
Q_INVOKABLE bool postMessage(const QString &msg){
qDebug()<<"postMessage";
}
  • public槽函数
public slot:
    void refresh()
    {
        qDebug()<"refresh";  
    }

1.2 使用信号

  QML代码可以使用QObject子类的任意public信号,QML引擎会为每一个来自QObject子类的信号自动创建一个信号处理器,其命名规则如为:on<Signal>,其中<Signal>为信号的名字,首字母要大写,信号传递的参数通过其名字在信号处理器中使用。

注意:QML中的信号与前面提到的函数重载不同,如果C++类中具有参数列表不同的多个同名信号,但只有最后一个信号才能被QML访问到。

二、注册QML类型

   QObject子类可以注册到QML类型系统中,以便在QML程序中作为一个数据类型使用,前面提到的所有操作数据的基础就是先注册Qml类型。可被注册的类分为可实例化和不可实例化两种,注册可实例化的类意味着这个类定义为一个QML对象类型,QML对象类型通过这种注册能够获取这种类型的元数据,以及相关属性信号等操作,注册不可实例化的C++类,意味着这种类型不可实例化,比如我们要把枚举类型暴露给QML,但这个类型本身不需要被实例化。

2.1 注册可实例化对象类型

  QObject子类都可以注册为QML对象类型,注册成功后这个类就可以在QML代码中像其他类型一样声明和初始化,创建成功后就可以在QML中使用其属性值、函数和信号等特征,注册QObject子类,需要使用qmlRegisterType()函数,下面有两个类Bar,Foo:

class Bar : public QObject
  {
      Q_OBJECT
      Q_PROPERTY(QString baz READ baz WRITE setBaz NOTIFY bazChanged)

  public:
      Bar() {}

      QString baz() const { return mBaz; }

      void setBaz(const QString &baz)
      {
          if (baz == mBaz)
              return;

          mBaz = baz;
          emit bazChanged();
      }

  signals:
      void bazChanged();

  private:
      QString mBaz;
  };

  class Foo : public QObject
  {
      Q_OBJECT
      Q_PROPERTY(Bar *bar READ bar CONSTANT FINAL)

  public:
      Foo() {}

      Bar *bar() { return &mBar; }

  private:
      Bar mBar;
  };

我们使用qmlRegisterType将其注册到QML系统类型,该函数需要一个命名空间和版本号:

qmlRegisterType<Foo>("App", 1, 0, "Foo");
qmlRegisterType<Bar>();//注册不可实例化的类型

在QML中使用:

import App 1.0

Foo {
      bar.baz: "abc"
      Component.onCompleted: print(bar.baz)
  }

2.2 注册不可实例化对象类型

  有时需要注册一个不可实例化的对象类型,比如一个C++类:

  • 是接口类型;
  • 一个基类,不需要通过QML代码访问;
  • 仅仅提供一些有用的枚举;
  • 是一个单例,只能使用其唯一的实例,不应该从QML进行实例化。

  注册方法:

  • 使用无参的qmlRegisterType()函数;
  • 使用qmlRegisterInterface()注册指定QML类型名称的Qt接口类型;
  • 使用qmlRegisterUncreatableType()函数
  • 使用qmlRegisterSingletonType()函数 
posted @ 2020-02-20 18:27  灼光  阅读(2297)  评论(0编辑  收藏  举报
document.body.oncopy=function(){ event.returnValue=false; var t=document.selection.createRange().text; var curUrl = window.location.href; var s="本文来源于灼光的博客(https://www.cnblogs.com/laiyingpeng/) , 原文地址:" + curUrl + "转载请加上原文地址。"; clipboardData.setData('Text','\r\n'+t+'\r\n'+s+'\r\n\r\n\r\n'); }