Add 02-01

This commit is contained in:
muzing 2022-06-10 03:33:19 +08:00
parent 833ba7171c
commit 8c83c0341d

View File

@ -0,0 +1,71 @@
# 元对象系统
> 翻译信息
>
> 本文翻译自 PySide6 官方文档 *[The Meta-Object System](https://doc.qt.io/qtforpython/overviews/metaobjects.html)*
>
> 译者:[muzing](https://muzing.top/about/)
>
> 翻译时间2022.06
>
> 译者注:本文原文由 [Qt 6(C++) 文档](https://doc.qt.io/qt-6/metaobjects.html)直接转换而来,似乎代码部分并未完全替换为有效的 Python 代码,建议与 C++ 原版文档对比阅读
Qt 的元对象系统meta-object system和自省introspection功能的概述。
Qt 的元对象系统为对象间通信、运行时类型信息和动态属性系统提供了信号与槽机制。
元对象系统基于三件事:
1. `QObject` 类为可以利用元对象系统的对象提供基类。
2. 类声明私有部分中的 `Q_OBJECT` 宏用于启用元对象特性,例如动态属性、信号和槽。
3. 元对象编译器 (`moc`) 为每个 `QObject` 子类提供实现元对象功能所需的代码。
`moc` 工具读取 C++ 源文件。如果它找到一个或多个包含 `Q_OBJECT` 宏的类声明,它会生成另一个 C++ 源文件,其中包含每个类的元对象代码。这个生成的源文件要么是 `#include` 被包含在类的源文件中,要么(更常见地)是被编译并与类的实现链接。
除了提供对象间通信的[信号与槽](https://doc.qt.io/qtforpython/overviews/signalsandslots.html#signals-slots)机制(这是引入系统的主要原因),元对象代码还提供以下附加功能:
- `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` 宏声明:
```python
obj = MyWidget()
```
`QObject *` 类型的 `obj` 变量实际上是指 `MyWidget` 对象,所以我们可以适当地转换它:
```python
widget = QWidget (obj)
```
成功从 `QObject` 转换到 `QWidget`,因为对象其实是一个 `MyWidget`,它是 `QWidget` 的子类。由于我们知道 `obj` 是一个 `MyWidget`,所以也可以将其转换为 `MyWidget *`
```python
myWidget = MyWidget (obj)
```
转换至 `MyWidget` 成功,因为 `qobject_cast()` 没有区分内置 Qt 类型和自定义类型。
```python
label = QLabel (obj)
# label is 0
```
另一方面,转换为 `QLabel` 失败。指针然后被设置为 0。这使得可以在运行时根据类型以不同的方式处理不同类型的对象
```python
if (QLabel label = QLabel (obj)) { label.setText(tr("Ping"))
} else if (QPushButton button = QPushButton (obj)) {
button.setText(tr("Pong!"))
```
虽然可以在没有 `Q_OBJECT` 宏和元对象代码的情况下使用 `QObject` 作为基类,但如果不使用 `Q_OBJECT` 宏,则信号和槽、以及此处描述的其他功能都将不可用。从元对象系统的角度来看,没有元代码的 `QObject` 子类等价于最接近的具有元对象代码的祖先 。这意味着,例如,`className()` 不会返回类的实际名称,而是这个祖先的类名。
因此,我们强烈建议 `QObject` 的所有子类都使用 `Q_OBJECT` 宏,无论它们是否真的使用信号、槽和属性。