在非 UI 线程中更新 UI (例如改变 QLabel 的文本) 应该使用 信号槽
或者 QMetaObject::invokeMethod()
,不要直接调用 widget 的函数,例如在非 UI 线程中直接调用 QLabel::setText(text)
就有可能让程序崩溃。有意思的是 Qt 4 时程序会直接奔溃退出,很容易发现问题,但在 Qt 5 里有时候没问题,有时候会在控制台有警告,有时候程序会退出,导致问题隐藏的比较深,所以最好的办法就是遵守规则不要直接调用,下面的程序展示了相关测试代码。
Because of limitations inherited from the low-level libraries on which Qt’s GUI support is built, QWidget and its subclasses are not reentrant. One consequence of this is that we cannot directly call functions on a widget from a secondary thread. If we want to, say, change the text of a QLabel from a secondary thread, we can emit a signal connected to QLabel::setText() or call QMetaObject::invokeMethod() from that thread. For example:
1 | void MyThread::run() { |
main.cpp
1 |
|
XThread 类
1 |
|
1 |
|
Widget 类
1 |
|
1 |
|
输出,发现有 2 个线程:
- 0x7fdcf660e040 是 XThread
- 0x7fdcf65001e0 是 Ui 线程
1 | XThread: XThread(0x7fdcf660e040) |
结果
1 | // 在 XThread 线程上下文里调用 |