Qt对象模型

一般的工具包使用回调机制,回调就是指向函数的指针,把这个指针传递给一个要被处理的函数,那么就可以在这个函数被处理时在适当的地方调用这个回调函数,回调机制主要有两个缺陷。第一,不是类型安全的,不能保证在调用回调函数时可以使用正确的参数;第二,是强耦合的,处理函数必须知道调用哪个回调函数。而Qt的信号与槽机制能克服了这些缺点。

信号能关联多个槽函数,而执行顺序与关联顺序相同。信号没有返回值,只是是void类型的。

connect函数的原型

QMetaObject::Connection QObject::connect(const QObject *sender,PointerToMemberFunction signal,const QObject *receiver,PointerToMemberFunction method,Qt::ConnectionType type=Qt::AutoConnection)

前面4个参数是常使用的,而最后一个参数代表关联的方式,有如下图选项,其中默认为Qt::AutoConnection

常量 描述
Qt::AutoConnection 自动关联,默认值
Qt::DirectConnection 直接关联,发射完信号后立即调用槽,只有槽执行完成返回后,发射信号处后面的代码才可以执行
Qt::QueuedConnection 队列关联,当控制返回接受者所在线程的事件循环后再执行槽,发射信号处后面的代码会立即执行
Qt::BlockingQueuedConnection 阻塞队列关联,类似上面那个,不过信号线程会一直阻塞,直到槽返回,当接受者存在信号线程不能使用,不然会死锁
Qt::UniqueConnection 唯一关联,标志,可以结合其他几种连接类型,使用按位或操作组合,主要是为了防止重复关联

再来看看disconnect()函数

bool QObject::disconnect(const QObject *sender,const char *signal,const QObject *recevier,const char *method)

可以用多种方法,最常规的是把connect的参数照着写一遍,也可以

disconnect(myObject,0,0,0); //断开与对象所有的信号的所有关联

disconnect(myObject,SIGNAL(mySignal()),0,0); //断开与指定信号的所有关联

disconnect(myObject,0,myRecevier,0);  //断开与指定对象的所有关联

需要注意的是有一个QSignalMapper类,称为信号映射器,可以实现对多个相同部件的相同信号进行映射,为其添加字符串或者数值参数,然后再发射出去。

属性系统

要在一个类中声明属性,该类必须继承自QObject类,还要在声明前使用了Q_PROPERTY()宏。如果是枚举类型,还需要使用Q_ENUMS()宏在元对象系统中进行注册,这样才可以使用setProperty()函数来使用该属性。

看一下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])
  • 如果MEMBER关键字没有被指定,则一个READ访问函数是必须的。它被用来读取属性值。理想的情况下,一个const函数用于此目的,并且它必须返回的是属性类型或const引用。比如:QWidget::focus是一个只读属性,通过READ函数QWidget::hasFocus()访问。

  • 一个WRITE访问函数是可选的,用于设置属性的值。它必须返回void并且只能接受一个参数,属性的类型是类型指针或引用,例如:QWidget::enabled具有WRITE函数QWidget::setEnabled()。只读属性不需要WRITE函数,例如:QWidget::focus没有WRITE函数。

  • 如果READ访问函数没有被指定,则MEMBER变量关联是必须的。这使得给定的成员变量可读和可写,而不需要创建READ和WRITE访问函数。如果需要控制变量访问,仍然可以使用READ和WRITE函数而不仅仅是MEMBER(但别同时使用)。

  • 一个RESET函数是可选的,用于将属性设置为上下文指定的默认值。例如:QWidget::cursor有READ和WRITE函数QWidget::cursor()和QWidget::setCursor(),同时也有一个RESET函数QWidget::unsetCursor(),因为没有可用的QWidget::setCursor()调用可以确定的将cursor属性重置为上下文默认的值。RESET函数必须返回void类型,并且不带任何参数。

  • 一个NOTIFY信号是可选的。如果定义了NOTIFY,则需要在类中指定一个已存在的信号,该信号在属性值发生改变时发射。与MEMBER变量相关的NOTIFY信号必须有零个或一个参数,而且必须与属性的类型相同。参数保存的是属性的新值。NOTIFY信号应该仅当属性值真正的发生变化时发射,以避免被QML重新评估。例如:当需要一个没有显式setter的MEMBER属性时,Qt会自动发射信号。

  • 一个REVISION数字是可选的。如果包含了该关键字,它定义了属性并且通知信号被特定版本的API使用(通常是QML);如果没有包含,它默认为0。

  • DESIGNABLE属性指定了该属性在GUI设计器(例如:Qt Designer)里的编辑器中是否可见。大多数的属性是DESIGNABLE (默认为true)。除了true或false,你还可以指定boolean成员函数。

  • SCRIPTABLE属性表明这个属性是否可以被一个脚本引擎操作(默认是true)。除了true或false,你还可以指定boolean成员函数。

  • STORED属性表明了该属性是否是独立存在的还是依赖于其它属性。它也表明在保存对象状态时,是否必须保存此属性的值。大多数属性是STORED(默认为true)。但是例如:QWidget::minmunWidth()的STROED为false,因为它的值从QWidget::minimumSize()(类型为QSize)中的width部分取得。

  • USER属性指定了属性是否被设计为用户可见和可编辑的。通常情况下,每一个类只有一个USER属性(默认为false)。例如: QAbstractButton::checked是(checkable)buttons的用户可修改属性。注意:QItemDelegate获取和设置widget的USER属性。

  • CONSTANT属性的出现表明属性是一个常量值。对于给定的object实例,常量属性的READ函数在每次被调用时必须返回相同的值。对于不同的object实例该常量值可能会不同。一个常量属性不能具有WRITE函数或NOYIFY信号。

  • FINAL属性的出现表明属性不能被派生类所重写。有些情况下,这可以用于效率优化,但不能被moc强制执行。必须注意不能覆盖一个FINAL属性。

需要注意的是Property()函数返回值为QVariant类型。使用setProperty()函数还可以设置动态属性,只需要将属性名设置为一个类中没有的属性即可。

my->setProperty("myValue",10); //动态属性,只对该实例有效

属性使用的自定义类型需要使用Q_DECLARE_METATYPE()宏注册,以便它们的值能被保存在QVariant对象中。这使得它们适用于在类定义时使用Q_PROPERTY()宏声明的静态属性,以及运行时创建的动态属性。

元对象系统

元对象系统基于三个条件   1.该类必须继承自QObject类。2.必须在类的私有声明区声明Q_OBJECT宏  3.元对象编译器Meta_Object为QObject的子类实现元对象特性提供必要代码。除了信号与槽,元对象系统还提供了一些其他特性。

  • QObject::metaObject()返回类关联的meta-object对象。

  • QMetaObject::className()在运行时以字符串的形式返回类名,无需C++编译器提供运行时类别信息(RTTI)的支持。

  • QObject::inherits()返回一个对象是否是QObject继承树上一个类的实例。

  • QObject::tr()和QObject::trUtf8()提供国际化支持,将字符串翻译成指定的语言。

  • QObject::setProperty()和QObject::property()通过名称动态设置和获取属性。

  • QMetaObject::newInstance()构造类的一个新实例。

qobject_cast()函数对QObject类进行动态类型转换,如果是正确的类型,则返回一个非零的指针。qobject_cast()函数和标准C++的dynamic_cast()功能类似,它的优点在于:不需要RTTI的支持,而且可以跨越动态连接库的转换。

猜你喜欢

转载自blog.csdn.net/weixin_38893389/article/details/81200228