QML自学之路(六)-用C++语言编写QML对象类型

8 篇文章 0 订阅
3 篇文章 0 订阅

Qt支持用C++语言编写自己的QML对象类型。得益于QML与Meta-object系统紧密结合,在QML程序中可以很容易的对QObject子类的属性、方法及信号进行访问。Qt提供的注册机制也比较简单,通过这个机制将C++编写的QML对象类型进行注册后,就可以在QML程序中使用自定义对象类型了。以下,我会结合实例讲解如何自定义QML对象类型以及如何对这些自定义对象类型进行注册。

一、对象类型定义

下面是一个C++定义QML对象类型的一个示例:

class Message : public QObject
{
    Q_OBJECT
    Q_PROPERTY(QString author READ author WRITE setAuthor NOTIFY authorChanged)
    Q_PROPERTY(QDateTime creationDate READ creationDate WRITE setCreationDate NOTIFY creationDateChanged)
    QML_ELEMENT
public:
    // ...
};

在以上这个例子中,需要重点关注QML_ELEMENT宏,这个宏用于声明这个类可以在QML语言中使用,并且声明这个类在QML程序中对应的对象类型名称为Message。

与QML_ELEMENT宏对应的是QML_NAMED_ELEMENT宏它与QML_ELEMENT宏功能类似,不同的是QML_NAMED_ELEMENT需要指定当前类在QML程序中对应的对象类型名称。例如,在以上示例中,可以将QML_ELEMENT替换为QML_NAMED_ELEMENT(CustomMessage),那么,这个类在QML程序中对应的对象类型名称为CustomMessage。(使用QML_ELEMENT及QML_NAMED_ELEMENT宏需要<QtQml/qqml.h>头文件)

对于一些复杂的对象类型,还需要借助其他一些宏进行声明。例如,如果想声明一个单例对象类型,需要使用QML_SINGLETON宏。下面是一个单例对象类型的示例:

class MySingleton : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    // Q_PROPERTY( ... )
public:
    // members, Q_INVOKABLE functions, etc.
};

在以上示例中,定义了一个名为MySingleTon的QML对象类型。QML引擎会通过类的默认构造函数创建一个唯一的MySingleton对象。这个对象与QML引擎生命周期相同,当QML引擎被析构时,这个对象也会被析构。如果希望QML引擎使用我们创建的对象作为单例对象,那么需要定义一个工厂方法。在这个方法中返回一个单例对象。

class MySingleton : public QObject
{
    Q_OBJECT
    QML_ELEMENT
    QML_SINGLETON
    // Q_PROPERTY( ... )

public:
    static MySingleton *create(QQmlEngine *qmlEngine, QJSEngine *jsEngine)
    {
        MySingleton *result = nullptr;
        // Create the object using some custom constructor or factory.
        // The QML engine will assume ownership and delete it, eventually.
        return result;
    }

    // members, Q_INVOKABLE functions, etc
};

在以上这个例子中,create是一个工厂函数,QML引擎通过调用这个函数获得单例对象。在使用单例对象时,我曾将犯过这样一个错误,在C++类中包含一个instance成员变量,又声明了一个静态get()函数返回这个instance对象。同时,C++类中还定义了一个默认构造函数。编写QML程序时,发现访问的不是C++类中的instance,后来我明白了,因为,QML中的用到的单例对象是QML引擎创建的另外一个对象而不是C++类中的instance。换句话说,这样定义的QML对象类型根本不是单例模式的。(如果用工厂函数替换get()函数就可以满足需求)。

有些时候,希望将一个已有类声明为一个QML对象类型,但是无法直接对这个类的源码进行修改(例如一些第三方库中包含的类)。对于这种情况,可以使用单独的一个结构体进行声明。在这个结构体中需要用QML_FOREIGN宏对这个类进行注册。以下是一个导出第三方类库中的类的示例:

struct Foreign
{
    Q_GADGET
    QML_FOREIGN(Immutable3rdParty)
    QML_NAMED_ELEMENT(Accessible3rdParty)
    QML_ADDED_IN_VERSION(2, 4)
    // QML_EXTENDED, QML_SINGLETON ...
};

在这个结构体中,声明Immutable3rdParty为要导出的类,这个类在QML程序中的对象类型名称为Accessible3rdParty。

还有些时候,需要对一个已有类进行扩展并导出为QML对象类型,如果这个类的源码无法修改,那么需要借助一个扩展类型来实现扩展功能,并用QML_EXTENDED宏对扩展类型进行注册。以下是对扩展类注册的一个例子:

struct QLineEditForeign
{
    Q_GADGET
    QML_FOREIGN(QLineEdit)
    QML_NAMED_ELEMENT(QLineEdit)
    QML_EXTENDED(LineEditExtension)
};

在这个例子中,LineEditExtension是一个扩展类,当QML程序中对QLineEdit类型对象的新增属性进行访问时,QML引擎会将QLineEdit对象作为参数调用LineEditExtension构造函数创建一个对象,并对这个新增属性进行访问。

以上提到的这些宏都在qqmlregistration.h头文件中定义。

二、将C++类注册为QML对象类型

任何一个QOjbect类的子类都可以注册为QML对象类型。将一个QObject子类注册为QML对象类型需要进行如下操作:

(1)在类的定义中添加QML_ELEMENT或者QML_NAMED_ELEMENT(<name>)宏

(2)在.pro文件中添加 CONFIG += qmltypes

(3)在.pro文件中为QML_IMPORT_NAME变量指定一个命名空间名称。所有导出的QML类型将注册到这个命名空间中

(4)在.pro文件中为QML_IMPORT_MAJOR_VERSION变量指定一个主版本编号。

通过以上操作就可以将工程中的QObject子类注册到指定的命名空间中了。

以下是一个QML对象类型的注册示例:

//.pro文件片段
CONFIG += qmltypes
QML_IMPORT_NAME = com.mycompany.messaging
QML_IMPORT_MAJOR_VERSION = 1

//qml代码片段
import com.mycompany.messaging 1.0
Message {
    author: "Amelie"
    creationDate: new Date()
}

在这个例子中,Message是一个用C++语言编写的QML对象类型。QML_IMPORT_NAME 变量指定将这个类注册到com.mycompany.messaging命名空间中。在qml程序中通过import语句对com.mycompany.messaging模块引入,就可以访问这个模块中注册的QML对象类型了。(通过以上方式实际上也同时定义了一个名为com.mycompany.messaging的模块)。

  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值