2021.5.29:QT——元对象与属性系统

学习自:Qt元对象和属性系统详解

QT是一个用标准C++编写的跨平台开发类库,它对标准C++进行了扩展,引入了元对象系统信号与槽属性等特征,这使得程序开发更加高效。

元对象系统(Meta-Object System)

QT的原对象系统提供了对象之间通信信号与槽机制运行时类型信息动态属性系统

元对象系统由以下三个基础组成:

  1. QObject是所有元对象系统类的基类
  2. 在一个类的private部分声明Q_OBJECT宏,使得类可以使用元对象的特性,比如动态属性信号与槽
  3. MOC(元对象编辑器)为每个QObject的子类提供了必要的代码实现元对象系统的特性。

该系统的运行过程:构建项目时,MOC工具读取C++源文件,当它发现类的定义中有Q_OBJECT宏时,它就会为这个类生成另外一个包含有元对象支持代码的C++源文件,这个生成的源文件连同类的实现文件一起被编译和连接。

除了信号与槽机制外,元对象还提供如下一些功能:

  • QObject :: metaObject()函数,返回类关联的元对象;元对象类QMetaObject包含了访问元对象的一些接口函数,例如QMetaObject::className()函数可以在运行时返回类的名称字符串:
    QObject * obj = new QPushButton;
    obj->metaObject()->className(); //返回QPushButton
  • QMetaObject::newInstance()函数,创建元对象类的一个新的实例;
  • QObject::inherits( const char * className)函数,判断一个对象实例是否是名为className的类或者QObject的子类的实例。
  • QObject::tr()QObject::trUtf8()函数可以用于翻译字符串,用于多语言界面设计,以后会专门介绍;
  • QObject::setProperty()QObject::property()函数用于通过属性名称动态设置和获取属性值

对于QObject及其子类,还可以使用qobject_cast() 函数进行动态投射(Dynamic Cast)。例如,QMyWidget是QWidget的子类并且在类定义中声明了Q_OBJECT宏。创建实例使用下面的语句:

QObject * obj = new QMyWidget;

变量obj定义为QObject指针,但是它实际指向QMyWidget——QWidget的子类,这就是C++中的多态

当然,我们也可以把一个已经定义了的obj指针强制转化为QMyWidget,即

QMyWidget * widget = qobject_cast<QWidget *>(obj);

投射为QMyWidget是成功的,因为qobject_cast()并不区分Qt内建的类型和用户自定义类型。但是,如果想将obj投射为QLabel则可能会失败,即:

QLabel * label = qobject_cast <QLabel *>(obj);

因为QMyWidget不是QLabel的子类。

使用动态投射,使得程序可以在运行时对不同的对象做不同的处理。

个人理解,动态投射就是多态强制类型转化的结合。

属性系统

属性定义

Qt提供了一个Q_PROPERTY()宏可以定义属性,它是基于元对象系统实现的。Qt属性系统与C++编译器无关,可以用任何标准的C++编译器编译定义了属性的Qt C++程序。

在QObject子类中,用宏Q_PROPERTY()定义属性,其格式如下:

Q_PROPERTY(type name (READ getFunction [WRITE setFunction] | MEMBER memberName
                      [(READ getFunction | WRITE setFunction)])
                       [RESET resetFunction]
                       [NOTIFY notifySignal]
                       [REVISION int]
                       [DESIGNABLE bool]
                       [SCRIPTABLE bool]
                       [STORED bool]
                       [USER bool]
                       [CONSTANT]
                       [FINAL]
           )

Q_PROPERTY宏定义一个返回值类型type名称name属性,用READ、WRITE关键字定义属性的读写函数,还有其他一些关键字定义属性的一些操作特性。属性的类型可以是QVariant支持的任何类型,也可以是用户自定义类型。

上文Q_PROPERTY宏定义属性的一些关键字的意义如下:

  • READ——一个读取属性值的函数,没有MEMBER关键字时必须设置READ
  • WRITE——一个设定属性值的函数,只读属性没有WRITE
  • MEMBER——一个与属性关联的成员变量,可读可写,无需再设置READ、WRITE
  • RESET——可选,一个设定属性缺省值的函数
  • NOTIFY——可选,设置一个信号,当属性值变化时发射该信号
  • DESIGNABLE——属性是否在Qt Designer可见,缺省为true
  • CONSTANT——指定属性值是个常数;对一个对象实例,READ指定的函数返回值是常数,但是每个实例的返回值可以不同。具有CONSTANT关键字的属性不能有WRITE和NOTIFY关键字
  • FINAL——属性不能被子类重载

QWidget类定义属性的一些例子如下:

Q_PROPERTY(bool focus READ hasFocus)
Q_PROPERTY(bool enabled READ isEnabled WRITE setEnabled)
Q_PROPERTY(QCursor cursor READ cursor WRITE setCursor RESET unsetCursor)

属性的使用

不管是否用READ和WRITE定义了接口函数,只要知道属性名称,就可以通过QObject::property()读取属性值,并通过QObject::setProperty()设置属性值。

例如:

QPushButton * button = new QPushButton;
QObject * obj = button;
object->setProperty("flat",true);
bool isFlat = object->property("flat");

动态属性

QObject::setProperty()函数可以在运行时为类定义一个新的属性,称之为动态属性。动态属性是针对类的实例定义的。

动态属性可以用QObject::property()查询,就如在类定义中用Q_PROPERTY宏定义的属性一样。

例如,在数据表编辑界面上,一些字段是必填字段,就可以在初始化界面时为这些字段的关联显示组件定义一个新的required属性,并设置值为“true”,如:

editName->setProperty("required","true");
comboSex->setProperty("required","true");
checkAgree->setProperty("required","true");

然后,可以应用下面的样式定义将这种必填字段的背景色设置为亮绿色:

*[required="true"]{background-color:lime}

类的附加信息

属性系统还有一个宏Q_CLASSINFO(),可以为类的元对象定义为(名称——值),就像Python中的Dict一样,例如:

class QMyClass : public QObject {
    Q_OBJECT
    Q_CLASSINFO("author","Wang")
    Q_CLASSINFO("company","UPC")
    Q_CLASSINFO("version","3.0.1")
public:
    ...
};

Q_CLASSINFO()宏定义附加类信息后,可以通过元对象的一些函数获取类的附加信息,如classinfo(int)获取某个附加信息,函数原型定义如下:

QMetaClassInfo QMetaObject :: classInfo(int index) const

返回值是QMetaClassInfo类型,有name()value()两个函数,可以获得类附加信息名称

posted @ 2021-05-31 21:19  ShineLe  阅读(270)  评论(0)    收藏  举报