QObject 是 Qt 的核心,核心特征是强大的无缝对象通信机制 signals and slots(信号与槽)。
用户可以使用 connect() 将信号连接到槽,也可以使用disconnect() 断开连接。为避免无止境的通知循环,还可以使用 blockSignals()暂时阻止信号。受保护函数connectNotify()和 disconnectNotify() 可以跟踪连接。
QObjects 在 object trees (对象树)中组织自己。当创建以另一个对象作为父对象的 QObject 时,该对象将自动将自身添加到父对象的 children() 列表中。父级获得对象的所有权。也就是说,它将自动删除其析构函数中的子级。用户可以按名称查找对象,也可以选择使用 findChild()或findChildren()。
每个对象都有一个 objectName(),它的类名可以通过相应的 metaObject() 找到(参见QMetaObject::className())。您可以使用 inherits() 函数确定对象的类是否继承 QObject 继承层次结构中的另一个类。
当对象被删除时,它会发出 destroyed() 信号,可以捕获此信号以避免对 QObjects 的悬空引用。
QObjects 可以通过 event() 接收事件,并过滤其他对象的事件(参阅 installEventFilter() and eventFilter())。可以重新实现 childEvent() 以捕获子事件。
QObject 还在 Qt 中提供了基本的定时器QTimer 支持。
注意
对于实现信号、槽或属性的任何对象, Q_OBJECT 宏都是必需的。您需要在源文件上运行 Meta Object Compiler。强烈建议在 QObject 的所有子类中使用此宏,无论它们是否实际使用信号、插槽和属性,因为如果不这样做可能会导致某些函数表现出奇怪行为。
所有 Qt 控件都继承了 QObject。isWidgetType() 函数返回对象是否实际上是控件。它比qobject_cast<QWidget *>(obj) 或 obj->inherits("QWidget") 快得多。
某些 QObject 函数(例如 children())返回 QObjectList,这是 QList<QObject *>的类型定义 。
线程亲和性 Thread Affinity
线程亲和性 能够强制使你的应用线程运行在特定的一个或多个cpu上。通过这种方式,可以消除操作系统进行调度过程导致线程迁移所造成的影响。
QObject 实例被具有线程亲和性,当 QObject 收到一个 queued signal 或一个posted event,槽或事件处理程序将在对象所在的线程中运行。
注意: 如果 QObject 没有线程亲和性(即,如果 thread() 返回零),或者如果它位于没有正在运行的事件循环的线程中,则它无法接收排队的信号或已发布的事件。
默认情况下,QObject 位于创建它的线程中。可以使用thread() 查询对象的线程亲和性,并使用 moveToThread() 更改对象的线程亲和性。
所有 QObject 必须与其父级位于同一线程中。因此:
- setParent() 如果涉及的两个 QObject 位于不同的线程中,则将失败。
- 当一个 QObject 移动到另一个线程时,它的所有子线程也将自动移动。
- 如果 QObject 有父级,则 moveToThread() 将失败。
- 如果 QObject 是在QThread::run()中创建的,则它们不能成为 QThread 对象的子对象,因为QThread 不存在于调用 QThread::run() 的线程中。
注意
QObject 的成员变量不会自动成为其子变量。父子关系必须通过传递指向子项的指针或调用 constructor来设置。如果没有此步骤,则在调用 setParent() 时,对象的成员变量将保留在旧线程中。
无复制构造函数或赋值运算符
QObject 既没有复制构造函数,也没有赋值运算符,这是设计使然。实际上,它们是声明的,在宏 Q_DISABLE_COPY() 的部分中。事实上,所有从QObject派生的Qt类(直接或间接)都使用这个宏来声明它们的复制构造函数和赋值运算符是私有的。
因此您应该使用指向 QObject(或指向 QObject 子类)的指针,否则您可能试图将 QObject 子类用作值。例如,如果没有复制构造函数,您不能使用 QObject 的子类作为要存储在其中一个容器类中的值。您必须存储指针。
自动连接
Qt的元对象系统提供了一种机制,可以在QObject子类及其子类之间自动连接信号和插槽。只要使用合适的对象名称定义对象,并且槽遵循简单的命名约定,就可以在运行时由 QMetaObject::connectSlotsByName() 函数执行此连接。
User Interface Compiler (uic ) 生成调用此函数的代码,以启用在使用Qt Designer 创建的表单上的控件之间执行自动连接。有关使用Qt Designer自动连接的更多信息,请参阅Using a Designer UI File in Your Application s。
动态属性
从Qt 4.2开始,动态属性可以在运行时添加到QObject实例中,也可以从QObject实例中删除动态属性。动态属性不需要在编译时声明,但它们提供了与静态属性相同的优点,并且使用相同的 API 进行操作 - 使用 property() 读取它们,使用 setProperty() 写入它们。
从Qt 4.3开始,动态属性由 Qt Designer支持,并且标准Qt控件和用户创建的form都可以被赋予动态属性。
国际化 (I18n)
所有QObject子类都支持Qt的翻译功能,从而可以将应用程序的用户界面翻译成不同的语言。
若要使用户可见的文本可翻译,必须将其包装在对 tr() 函数的调用中。 Writing Source Code for Translation 文档中对此进行了详细解释。
另请参见 QMetaObject, QPointer, QObjectCleanupHandler, Q_DISABLE_COPY(), and Object Trees & Ownership.