计算机
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 5
### 目录 - [信号连接检查 (isSignalConnected)](#信号连接检查-issignalconnected) - [定时器机制 (Timers)](#定时器机制-timers) - [元对象系统 (Meta-Object System)](#元对象系统-meta-object-system) - [线程亲和性与移动 (Thread Affinity & MoveToThread)](#线程亲和性与移动-thread-affinity--movetothread) - [发送者信息 (Sender Information)](#发送者信息-sender-information) - [其他重要方法与属性](#其他重要方法与属性) --- ### 信号连接检查 (isSignalConnected) [原片 @ 00:00](https://www.bilibili.com/video/BV1Q8411d7XM?t=0)* 在 Qt 中,有时需要判断某个信号是否已经连接到槽函数或其他信号。 - **方法**: `bool QObject::isSignalConnected(QPrivateSignal signal) const` (注:Qt 5.15+ 版本中该函数为公共接口,但在视频中演示了通过封装受保护方法来使用的情况,或者针对特定内部机制的检查)。 - **返回值**: 如果信号至少有一个连接(Slot 或 Signal),返回 `true`;否则返回 `false`。 - **代码示例**: - 创建一个对象 `o1` 和 `o2`。 - 将 `o1` 的信号 `objectNameChanged` 连接到 `o2` 的槽。 - 调用 `o1->isSignalConnected(...)` 进行检查。 - 视频演示中,由于直接调用可能受限(取决于 Qt 版本或访问权限),讲师在子类中封装了一个公开方法 `IsSignalConnected` 来调用底层的检查逻辑。 - 运行结果显示:当连接建立后返回 `true`;注释掉连接代码后返回 `false`。 ### 定时器机制 (Timers) [原片 @ 08:10](https://www.bilibili.com/video/BV1Q8411d7XM?t=490)* Qt 提供了基于事件循环的软件定时器支持。 - **启动定时器**: - `int startTimer(int interval, Qt::TimerType timerType = Qt::CoarseTimer)` - 参数 `interval`: 超时时间(毫秒)。 - 参数 `timerType`: - `Qt::CoarseTimer` (默认): 粗粒度定时器,精度较低,适合一般场景。 - `Qt::PreciseTimer`: 精确定时器,保证间隔准确。 - `Qt::VeryCoarseTimer`: 非常粗粒度,只保留小时精度。 - **返回值**: 返回一个唯一的定时器 ID (`int`)。 - **处理定时器事件**: - 重写虚函数 `void timerEvent(QTimerEvent *event)`。 - 在该函数中可以获取到触发事件的定时器 ID (`event->timerId()`)。 - **停止定时器**: - `void killTimer(int id)` - 使用 `startTimer` 返回的 ID 来停止特定的定时器。 - **注意事项**: - 如果一个对象没有父对象且被删除,定时器会自动停止。 - 如果对象在定时器超时前被销毁,则不会收到 `timerEvent`。 - **一次性定时器**: `startTimer` 默认是周期性的。如果需要一次性定时器,通常需要使用 `QTimer` 类配合 `Qt::Once` 连接,或者在 `timerEvent` 中手动调用 `killTimer`。 - **动态控制**: 可以在 `timerEvent` 中通过计数器实现“执行 N 次后停止”。例如,使用静态变量或成员变量计数,达到阈值时调用 `killTimer`。 - **移动线程的影响**: 当对象通过 `moveToThread` 移动时,现有的定时器会被重置(重新计算剩余时间),这可能导致定时器永远无法超时(如果频繁移动的话)。 ### 元对象系统 (Meta-Object System) [原片 @ 17:45](https://www.bilibili.com/video/BV1Q8411d7XM?t=1065)* 元对象系统是 Qt 的核心机制之一,提供了运行时类型信息和动态属性支持。 - **获取元对象**: - `const QMetaObject *metaObject() const` - 返回描述当前类的 `QMetaObject` 指针。 - **什么是元对象?** - 每个继承自 `QObject` 的类都有一个对应的元对象。 - 元对象存储了关于类的信息:类名、基类名、属性、信号、槽等。 - **一对多关系**: 一个类只有一个元对象,但可以有多个实例对象。所有实例共享同一个元对象。 - **访问方式**: 1. 通过对象实例: `obj->metaObject()->className()` 2. 通过静态方法 (不需要实例): `MyClass::staticMetaObject.className()` 或使用 `qobject_cast` 相关的宏。 - **应用场景**: - 信号与槽的连接机制依赖于此。 - 动态属性系统 (Dynamic Properties)。 - 反射功能(如获取类名、枚举值字符串化等)。 ### 线程亲和性与移动 (Thread Affinity & MoveToThread) [原片 @ 24:30](https://www.bilibili.com/video/BV1Q8411d7XM?t=1470)* Qt 对象具有线程亲和性 (Thread Affinity),即对象的事件处理发生在其所在的线程中。 - **移动对象到线程**: - `void moveToThread(QThread *targetThread)` - 将对象及其所有子对象移动到目标线程。 - **效果**: 对象的 `eventLoop` 将在新线程中运行,所有后续的事件处理都在新线程进行。 - **约束条件**: - **父对象约束**: 只有当对象**没有父对象**时,才能被移动(作为根节点)。如果对象有父对象,它必须留在父对象所在的线程中。 - **树状结构**: 移动一个对象会带动整个子树一起移动。 - **错误情况**: 尝试移动一个有父对象的非根节点会失败(通常会断言错误或无效果)。 - **获取当前线程**: - `QThread *thread() const` - 获取对象当前所在的线程。 - 获取主线程: `QCoreApplication::instance()->thread()`。 - **移回主线程**: - 可以将对象移回主线程: `obj->moveToThread(QCoreApplication::instance()->thread())`。 - **特殊行为**: - **定时器重置**: 移动过程中,活跃的定时器会在新线程中重新启动,计时器间隔重置。如果频繁移动对象,定时器可能永远不会超时。 - **事件分发**: 移动完成后,发送到该对象的新事件会在目标线程中处理。之前排队的事件可能在原线程处理完毕(取决于具体实现细节,通常建议在移动前清空队列或确保状态一致)。 ### 发送者信息 (Sender Information) [原片 @ 40:00](https://www.bilibili.com/video/BV1Q8411d7XM?t=2400)* 在槽函数内部,可以获取发送信号的对象信息。 - **获取发送者对象**: - `QObject *sender() const` - 返回指向发出信号的对象的指针。 - **注意**: 如果在槽函数内部被调用,返回的是信号源对象。如果不在信号处理的上下文中调用,返回 `nullptr`。 - **获取信号索引**: - `int senderSignalIndex() const` - 返回发送者对象中触发当前槽函数的信号的索引号。 - 用于区分同一个槽函数是被哪个具体的信号触发的(特别是在信号重载或多个信号连接到同一个槽时)。 - **示例**: - 在 `mystart` 槽函数中,打印 `sender()->objectName()` 可以知道是哪个对象发出了信号。 - 结合 `senderSignalIndex()` 可以确定是第几个信号触发了回调。 ### 其他重要方法与属性 [原片 @ 56:00](https://www.bilibili.com/video/BV1Q8411d7XM?t=3360)* - **属性系统 (Property System)**: - `Q_PROPERTY` 宏用于声明属性。 - 属性允许在运行时读写数据,支持信号通知 (`notify`)。 - 动态属性: 可以使用 `setProperty(const char *name, const QVariant &value)` 和 `property(const char *name)` 在运行时动态添加和获取属性,无需在编译时声明。 - **国际化 (Internationalization)**: - `tr(const char *sourceText, ...)` - 用于文本翻译,支持多语言切换。 - **禁止拷贝与赋值**: - `QObject` 明确禁用了拷贝构造函数和赋值运算符 (`Q_DISABLE_COPY(QObject)`)。 - **原因**: `QObject` 基于标识符 (Identity) 而非值 (Value)。对象具有父子关系、唯一 ID 和生命周期管理,拷贝会导致状态混乱(如双重删除、父子关系断裂)。 - **事件过滤器**: - `installEventFilter(QObject *filterObj)` - `removeEventFilter(QObject *filterObj)` - 用于拦截发送给对象的事件。
peipeo
2026年5月27日 17:53
转发文档
收藏文档
上一篇
下一篇
手机扫码
复制链接
手机扫一扫转发分享
复制链接
Markdown文件
PDF文档(打印)
分享
链接
类型
密码
更新密码