QObject 类是所有 Qt 对象的基类。
QObject 是 Qt 对象模型的核心。该模型的核心特征是一种非常强大的无缝对象通信机制,称为信号和槽。您可以使用 connect() 将信号连接到插槽,并使用 disconnect() 破坏连接。为避免永无止境的通知循环,您可以使用 blockSignals() 临时阻止信号。
QObjects 通过对象树组织。当您以另一个对象作为父对象创建 QObject 时,该对象将自动将自身添加到父对象的 children() 列表中。父级获得对象的所有权;即,它将自动删除其析构函数中的子级。
每个对象都有一个 objectName(),它的类名可以通过相应的 metaObject() 找到(参见 QMetaObject::className())。可以通过使用inherits() 函数来确定对象的类是否继承了QObject 继承层次结构中的另一个类。
当一个对象被删除时,它会发出一个destroy() 信号。您可以捕获此信号以避免对 QObjects 的悬空引用。
QObjects可以通过event()接收事件,过滤其他对象的事件。有关详细信息,请参阅 installEventFilter() 和 eventFilter()。
QObject 在 Qt 中提供了基本的计时器支持。
请注意,对于任何实现信号、槽或属性的对象,Q_OBJECT 宏都是必需的。您还需要在源文件上运行 Meta Object 编译器。强烈建议在 QObject 的所有子类中使用此宏,无论它们是否实际使用信号、槽和属性,因为不这样做可能会导致某些函数表现出奇怪的行为。
线程亲和性
QObject 实例被称为具有线程亲和性,或者说它存在于某个线程中。当 QObject 接收到排队的信号或发布的事件时,插槽或事件处理程序将在对象所在的线程中运行。
默认情况下,QObject 存在于创建它的线程中。可以使用 thread() 查询对象的线程亲和性,并使用 moveToThread() 更改对象的线程亲和性。
所有 QObject 必须与其父对象存在于同一线程中。最后:
如果涉及的两个 QObject 存在于不同的线程中,setParent() 将失败。
当一个 QObject 被移动到另一个线程时,它的所有子对象也将被自动移动。
如果 QObject 有父对象,则 moveToThread() 将失败。
如果 QObjects 在 QThread::run() 中创建,它们不能成为 QThread 对象的子对象,因为 QThread 并不存在于调用 QThread::run() 的线程中。
注意:QObject 的成员变量不会自动成为它的子变量。必须通过将指针传递给子构造函数或调用 setParent() 来设置父子关系。如果没有这一步,调用 moveToThread() 时对象的成员变量将保留在旧线程中。
没有复制构造函数或赋值运算符
QObject 既没有复制构造函数也没有赋值运算符。这是设计使然。实际上,它们是被声明的,但是在一个带有宏 Q_DISABLE_COPY() 的私有部分中。事实上,所有从 QObject 派生的 Qt 类(直接或间接)都使用这个宏来声明它们的复制构造函数和赋值运算符是私有的。
自动连接
Qt 的元对象系统提供了一种机制来自动连接 QObject 子类及其子类之间的信号和槽。只要用合适的对象名称定义对象,并且槽遵循简单的命名约定,这种连接就可以在运行时由 QMetaObject::connectSlotsByName() 函数执行。
动态属性
从 Qt 4.2 开始,可以在运行时向 QObject 实例添加和删除动态属性。 动态属性不需要在编译时声明,但它们提供与静态属性相同的优势,并且使用相同的 API 进行操作 - 使用 property() 读取它们并使用 setProperty() 写入它们。
从 Qt 4.3 开始,Qt Designer 支持动态属性,标准 Qt Widge可以被赋予动态属性。
国际化 (I18n)
所有 QObject 子类都支持 Qt 的翻译功能,从而可以将应用程序的用户界面翻译成不同的语言。
为了使用户可见的文本可翻译,它必须包含在对 tr() 函数的调用中。