警告
本节包含从C++自动翻译到Python的代码片段,可能包含错误。
元对象系统¶
Qt的元对象系统和内省功能的概述。
Qt的元对象系统提供了用于对象间通信的信号和槽机制、运行时类型信息和动态属性系统。
元对象系统基于以下三点:
moc
工具读取一个 C++ 源文件。如果它发现一个或多个包含 Q_OBJECT
宏的类声明,它会生成另一个 C++ 源文件,其中包含这些类的元对象代码。这个生成的源文件要么被 #include
到类的源文件中,要么更常见的是,与类的实现一起编译和链接。
除了提供信号和槽机制用于对象之间的通信(引入该系统的主要原因)之外,元对象代码还提供了以下附加功能:
metaObject()
返回类的关联meta-object
。
className()
在运行时返回类名作为字符串,而不需要通过C++编译器支持的原生运行时类型信息(RTTI)。
inherits()
函数返回一个对象是否是继承自QObject
继承树中指定类的实例。
tr()
用于国际化字符串的翻译。
setProperty()
和property()
动态地通过名称设置和获取属性。
newInstance()
构造类的新实例。
也可以对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
宏,无论它们是否实际使用信号、槽和属性。
另请参阅