1、Qt的元对象系统
Qt的元对象提供
对象间通信的信号和槽机制、运行时类型信息和动态属性系统。
QT RTTI 运行时类型识别技术(运行时类型信息
)
除了C++为我们提供的两种RTTI运算符(
dynamic_cast 和 typeid)外,qt也为我们提供了两种运行时类型识别机制:
(1)
qobject_cast
(2)
Qobject::inherits()
QT对象间的交流(槽函数)
QObject::connect()函数的原型是 [static] QMetaObject::Connection QObject::connect(const QObject *sender, const char *signal, const QObject *receiver, const char *method, Qt::ConnectionType type = Qt::AutoConnection)
参数Qt::ConnectionType type 就是Qt中信号与槽的连接方式。
默认连接:也称为AutoConnection,根据信号和槽所在的对象是否在
同一线程来决定连接方式。如果
信号和槽在同一线程,则使用DirectConnection;如果
信号和槽在不同线程,则使用
QueuedConnection。
直连(DirectConnection),信号在哪,就在哪个线程执行。这种连接方式
最好只在同一线程中使用。
队列连接(QueuedConnection),无论信号和槽在同一线程还是不同线程,
槽函数不会立刻执行,等到接受者的
当前执行的函数执行完才会执行槽函数。这种连接方式中,槽函数不会立刻执行,
会等待接收对象的当前线程完成当前的任务后,在事件循环中执行。
阻塞队列连接(BlockingQueuedConnection),这种连接方式与队列连接类似,槽函数调用时机相同,只是会在
发送者所在的线程会阻塞,直到槽函数运行完,发送者和接受者绝对不能在同一个线程。
唯一连接:(Qt::UniqueConnect),
一个信号只能有一个槽连接,多个会失败。
可以使用|与以上四种结合使用。
优点:
类型安全:信号和槽的签名必须是等同的,即信号的参数类型和参数个数必须与接收该信号的槽的参数类型和参数个数相同(
信号参数数大于等于槽的参数)。
松散耦合:
信号和槽机制减弱了Qt对象的耦合度。激发信号的Qt对象无须知道是哪个对象的哪个槽需要接收它发出的信号,而对象的槽也不知道是哪些信号关联了自己。这样,一个对象可以在不等待接收者的响应下继续执行,提高了程序的响应性能。
即使关联的对象在运行时被删除,应用程序也不会崩溃。
异步通信:信号和槽机制可以实现异步通信,
一个对象可以在不等待接收者的响应下继续执行,提高了程序的响应性能。
事件驱动:在Qt中的图形界面编程常常与事件处理有关。信号与槽机制使得处理事件变得更加方便,能够
轻松地处理按钮点击、鼠标事件等。
缺点:
速度较慢。与回调函数相比
,信号和槽机制运行速度比直接调用非虚函数慢
10倍。
原因:1、需要定位接收对象的信号(
找到对象位置)。2、安全地遍历所有关联槽(
一个对象有多个槽,需要一个一个对比)
3、编组解组
传递参数 4、
多线程的时候,信号需要排队等待。(然而,与创建对象的new操作及删除对象的delete操作相比,信号和槽的运行代价只是他们很少的一部分。信号和槽机制导致的这点性能损耗,对实时应用程序是可以忽略的。)

动态属性:动态使用属性,可以随时删除和增加属性
在Qt中我们可以使用宏
Q_PROPERTY()宏来实现。一个属性可以使用常规函数
QObject::property()和QObject::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] //不能被重写
)
1. type name
属性类型可以是
QVariant支持的任何类型,也可以是用户定义的类型;
2. READ 和 MEMBER
如果没有MEMBER,则必须要有READ。
READ 后面定义获取属性值的函数,该函数是const;
WRITE 设置属性值,是可选的;
MEMBER 如果一个属性不需要 READ ,但又想使用属性系统,可以使用MEMBER来注册,MEMBER后面是成员变量的名字;
3. RESET
可选,将属性设置为默认值,该RESET函数必须返回void并且不带参数。
4. NOTIFY
可选,NOTIFY 后面跟该类中已经定义的一个信号函数,只要该属性的值发生更改,就会发出该信号。这个信号函数必须采用零个或一个参数,
该参数必须与属性的类型相同。
5. REVISION int
可选,版本信息(通常用于QML)。
6. DESIGNABLE bool
可选,表示属性是否能在GUI设计工具的属性编辑器中可见(例如,Qt Designer)。大多数属性是DESIGNABLE(默认为true)。
7. SCRIPTABLE bool
可选,SCRIPTABLE属性表示脚本引擎是否应该可以访问此属性(默认为true)
8. STORED bool
可选,该属性是单独存在还是从其他值中获取的。大部分是true,一个反例是QWidget::minimumWidth()的值从QWidget::minimumSize()中获取,因此它的STORED为false。
9. USER bool
可选,表示是否可以被用户所编辑。
10. CONSTANT
可选,CONSTANT表明属性值是常量,不可更改,因此不能有WRITE方法或NOTIFY信号。对于给定的对象实例,常量属性的READ方法每次调用时都必须返回相同的值。
对于对象的不同实例,该常数值可以是不同的。
11. FINAL
可选,FINAL表示属性不会被派生类覆盖,在某些情况下,这可用于性能优化。
示例演示

定义多个动态属性

添加动态属性,并将属性添加到元对象系统,让它成为类的一员

删除动态属性,
使用removeProperty函数将其从元对象中删除