计算机
c base
c++ 基础 作用域及生命周期
c++ template
c++ 内存视角
c++ 函数
c++ 基础 基础语法
c++ 性能
c++ 类 基础
c++ 类 对象模型 类析构
c++ 类 设计模式
C++ STL
cmake
CMAKE环境搭建 windows
创建第一个cmakelists.txt
构建稍复杂的项目
动态链接库
EX1
EX1 START
EX1 ANSWER
EX2
EX2 START
EX2 ANSWER
EX3
EX3 START
EX3 ANSWER
变量
控制流程
函数和宏
查找和使用外部库
生成器表达式
qt
qt c++
qt index
qt qml quick
qt ui
qt 多线程
理解QObject 1
理解QObject 4
C++ 技巧 反射
理解QObject 2
理解QObject 3
理解QObject 6
理解 QObject 5
QCoreApplication
QApplication
数据结构
PC问题监控及排查
PC程序性能优化
OS
TOOL
编程漫谈
sealos+frp,搭建内网穿透
host主机配置
C++实战 主题
多线程
生产者-消费者流水线
IO
网络
Bilinotes搭建
编译原理
WEB开发
TS
HTML CSS JAVASCRIPT
本站点使用 MrDoc 构建
-
+
理解QObject 2
## 目录 1. [childEvent 虚函数](#1-childevent-虚函数) 2. [获取子对象列表 (children)](#2-获取子对象列表-children) 3. [信号与槽的连接 (Connect)](#3-信号与槽的连接-connect) 4. [信号连接到信号](#4-信号连接到信号) 5. [连接类型 (ConnectionType)](#5-连接类型-connectiontype) 6. [AI 总结](#ai-总结) --- ## 1. childEvent 虚函数 在 `QObject` 类中,`childEvent` 是一个重要的受保护(protected)虚函数。 * **访问权限**:它是 `protected` 的,意味着只有子类可以访问和重写它,外部类无法直接调用。 * **功能**:用于处理子对象相关的事件,例如子对象的添加或移除。 * **参数**:接收一个 `QChildEvent *event` 指针。 * **事件类型**: * `ChildAdded`:子对象加入时触发。 * `ChildRemoved`:子对象移除时触发。 **代码示例**: 在子类中重写 `childEvent` 来监听变化: ```cpp void MyObject::childEvent(QChildEvent *event) { qDebug() << "Child event received:"; qDebug() << "Type:" << event->type(); // 输出事件类型 // 调用父类的实现以完成默认处理 QObject::childEvent(event); } ``` **运行结果观察**: 当创建子对象(如 `new MyObject(parent)`)时,父对象的 `childEvent` 会被调用,打印出 `ChildAdded` 事件。同样,当手动设置 `parent = nullptr` 时,会触发 `ChildRemoved` 事件。 ## 2. 获取子对象列表 (children) `QObject` 提供了 `children()` 函数来获取当前对象的直接子对象列表。 * **返回值**:`QObjectList`。 * **特性**:只返回**直接**子对象(Direct Children),不会递归返回孙子辈对象。 **代码示例**: ```cpp // o1 的子对象是 o2 // o2 的子对象是 o3 qDebug() << o1->children(); // 输出包含 o2 的列表 // 注意:这里不会显示 o3,因为 o3 是 o2 的子对象,不是 o1 的直接子对象 ``` 如果将 `o3` 也设为 `o1` 的子对象(即 `o3` 的 parent 改为 `o1`),那么 `o1->children()` 就会同时包含 `o2` 和 `o3`。 ## 3. 信号与槽的连接 (Connect) `connect` 是 `QObject` 的核心功能之一,也是 QT 对 C++ 语言的扩展(通过元对象系统 Meta Object System)。 ### 字符串形式的 Connect (旧式写法) 这是 QT 早期版本常用的方式,使用宏 `SIGNAL` 和 `SLOT` 来包装函数签名。 * **语法**: ```cpp QObject::connect(sender, SIGNAL(signalName(parameters)), receiver, SLOT(slotName(parameters))); ``` * **宏的参数格式**:`类型 名称`(例如 `int value`)。虽然有些情况下只写类型也可以,但标准建议包含名称。 * **限制**:这种基于字符串的匹配机制比较松散,但在编译期无法检查错误。在某些 QT 版本或配置下,接收端的函数必须显式标记为 `slot`(或者在头文件中声明 `Q_SLOTS` / `slots:`)。 **示例:连接信号到槽** 假设我们要让 `o1` 改名时,`o2` 的名字也跟着改。 1. **定义信号**:`objectNameChanged(const QString &name)` 2. **定义槽**:需要一个能接受 `QString` 的函数。由于 `setObjectName` 是普通成员函数,为了兼容旧的字符串连接语法,可能需要自定义一个槽函数: ```cpp // 在 MyObject 类中 public slots: void setMyObjectName(const QString &name) { setObjectName(name); // 调用原来的逻辑 } ``` 3. **连接**: ```cpp QObject::connect(o1, SIGNAL(objectNameChanged(QString)), o2, SLOT(setMyObjectName(QString))); ``` ### 新式 Connect (函数指针形式) 虽然视频主要演示了字符串形式,但也提到了基于函数指针的新式写法(C++11 lambda 等),它提供了编译期类型检查,更安全。 ## 4. 信号连接到信号 信号不仅可以连接到槽,还可以连接到另一个信号。这通常用于“信号转发”。 **场景**: 有一个按钮(Button),点击时发出 `clicked()`。我们有一个窗口(Window),希望当按钮被点击时,窗口也能发出一个自定义信号 `windowClicked()`。 **代码逻辑**: ```cpp // 将按钮的信号连接到窗口的信号 connect(button, SIGNAL(clicked()), window, SIGNAL(windowClicked())); ``` 这样,当用户点击按钮时,`button` 发出 `clicked`,紧接着 `window` 也会发出 `windowClicked`。这就好比把 `button` 的事件转发给了 `window`。 ## 5. 连接类型 (ConnectionType) `connect` 函数的最后一个参数是 `Qt::ConnectionType`,决定了信号触发时槽函数的执行方式。 | 类型 | 描述 | | :--- | :--- | | **Qt::AutoConnection** (默认) | **自动判断**。如果发送者和接收者在同一个线程,则视为 `DirectConnection`;如果在不同线程,则视为 `QueuedConnection`。 | | **Qt::DirectConnection** | **直接连接**。信号发出后,槽函数立即在当前线程(发送者线程)同步执行。 | | **Qt::QueuedConnection** | **队列连接**。信号发出后,槽函数不会立即执行,而是放入接收者线程的事件队列中。当接收者线程的控制流回到事件循环(Event Loop)时,槽函数才会被执行。适用于跨线程通信。 | | **Qt::BlockingQueuedConnection** | **阻塞队列连接**。类似于 `QueuedConnection`,但发送者线程会**阻塞等待**,直到接收者线程执行完槽函数并返回后才继续。 <br> **警告**:如果发送者和接收者在同一线程,会导致**死锁**(Deadlock),因为发送者线程在等对方,而对方线程因为发送者没释放控制权而无法处理队列中的消息。 | | **Qt::UniqueConnection** | **唯一连接**。这是一个标志位(Flag),不能单独使用,必须与其他类型结合(使用位或 `|`)。<br> 如果尝试建立重复的连接(相同的信号连到相同的槽),连接会失败并返回 false。这有助于防止重复连接导致的槽函数被多次调用。<br> 引入于 QT 4.6。 | **UniqueConnection 示例**: ```cpp // 尝试连接两次 bool ret1 = QObject::connect(o1, SIGNAL(valueChanged(int)), o2, SLOT(onValueChanged(int)), Qt::AutoConnection); bool ret2 = QObject::connect(o1, SIGNAL(valueChanged(int)), o2, SLOT(onValueChanged(int)), Qt::AutoConnection | Qt::UniqueConnection); // ret1 成功,ret2 失败(因为连接已存在) // 如果使用 UniqueConnection,第二次连接会失败,槽函数只会执行一次 ``` ## AI 总结 本视频深入讲解了 `QObject` 类中几个关键功能的用法,重点包括: 1. **`childEvent`**:通过重写此受保护虚函数,开发者可以拦截和处理子对象的添加与移除事件。 2. **`children()`**:用于获取直接子对象列表,不递归查找后代。 3. **信号与槽机制**:详细演示了基于字符串的 `SIGNAL` 和 `SLOT` 宏的使用方式,强调了其参数格式要求以及槽函数声明的注意事项。同时也展示了信号转发(信号连信号)的技巧。 4. **连接类型**:全面解析了 `AutoConnection`、`DirectConnection`、`QueuedConnection` 和 `BlockingQueuedConnection` 的区别,特别是它们在多线程环境下的行为差异及潜在的死锁风险。最后介绍了 `UniqueConnection` 标志,用于防止重复连接。
peipeo
2026年5月27日 17:50
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码