警告

本节包含从C++自动翻译到Python的代码片段,可能包含错误。

元对象系统

Qt的元对象系统和内省功能的概述。

Qt的元对象系统提供了用于对象间通信的信号和槽机制、运行时类型信息和动态属性系统。

元对象系统基于以下三点:

  1. QObject 类为可以利用元对象系统的对象提供了一个基类。

  2. Q_OBJECT 宏用于启用元对象功能,例如动态属性、信号和槽。

  3. 元对象编译器(moc)为每个QObject子类提供了实现元对象功能所需的代码。

moc 工具读取一个 C++ 源文件。如果它发现一个或多个包含 Q_OBJECT 宏的类声明,它会生成另一个 C++ 源文件,其中包含这些类的元对象代码。这个生成的源文件要么被 #include 到类的源文件中,要么更常见的是,与类的实现一起编译和链接。

除了提供信号和槽机制用于对象之间的通信(引入该系统的主要原因)之外,元对象代码还提供了以下附加功能:

也可以对QObject类使用qobject_cast()进行动态类型转换。qobject_cast()函数的行为类似于标准的C++ dynamic_cast(),其优点是不需要RTTI支持,并且可以在动态库边界之间工作。它尝试将其参数转换为尖括号中指定的指针类型,如果对象是正确类型(在运行时确定),则返回非零指针,如果对象的类型不兼容,则返回None

例如,假设 MyWidget 继承自 QWidget 并使用 Q_OBJECT 宏声明:

obj = MyWidget()

obj 变量,类型为 QObject *,实际上引用了一个 MyWidget 对象,因此我们可以适当地进行类型转换:

widget = QWidget(obj)

QObject到QWidget的转换是成功的,因为该对象实际上是一个MyWidget,它是QWidget的子类。既然我们知道obj是一个MyWidget,我们也可以将其转换为MyWidget *

myWidget = MyWidget(obj)

转换为MyWidget是成功的,因为qobject_cast()不会区分内置的Qt类型和自定义类型。

label = QLabel(obj)
# label is 0

另一方面,转换为QLabel失败。然后指针被设置为0。这使得在运行时根据类型不同处理不同类型的对象成为可能:

if QLabel label = QLabel(obj):
   label.setText(tr("Ping"))
elif QPushButton button = QPushButton(obj):
   button.setText(tr("Pong!"))

虽然可以在不使用Q_OBJECT宏和元对象代码的情况下使用QObject作为基类,但如果不使用Q_OBJECT宏,信号和槽以及这里描述的其他功能都将不可用。从元对象系统的角度来看,没有元代码的QObject子类等同于其具有元对象代码的最接近的祖先。这意味着,例如,className()将不会返回您类的实际名称,而是返回此祖先的类名。

因此,我们强烈建议所有QObject的子类都使用Q_OBJECT宏,无论它们是否实际使用信号、槽和属性。