在 Qt 中,所有小部件都应该存在于主 GUI 线程中。所有其他线程不应该直接从主线程访问小部件,Qt 在这里不保证线程安全。解决办法是什么?使用 Qt 的内置队列机制。有两种方法。
- 如果第二个线程中有 QObject 派生类,则可以使用 Qt::QueuedConnection Qt::signal/slot 连接。您也可以使用默认的 Qt::AutoConnection,但我更喜欢明确说明我需要什么。
从文档:
(Qt::AutoConnection) 如果接收者位于发出信号的线程中,则使用 Qt::DirectConnection。否则,使用 Qt::QueuedConnection。连接类型在信号发出时确定。
- 如果您的第二个线程中没有任何 QObject - 使用 QMetaObject::invokeMethod。
如何为调用者提供指向被调用者的指针?我建议使用闭包(带有捕获的 lambda)。
但要小心你的对象的生命周期。您现在有责任检查捕获的指向小部件的指针指向的有效小部件是否比非 GUI 线程的生命周期长。
根据您的代码,第二个变体更适合您。有一个小例子:
// guiwidget.h
class GuiWidget : public QWidget
{
Q_OBJECT
public:
GuiWidget(QWidget *parent = nullptr);
~GuiWidget() {};
// public function for variant 2
void function(int data) {
// update widget
}
// slot for variant 1
public slots:
void function_slot(int data) {
// update widget
}
};
在你的 .cpp 文件中的某个地方:
GuiWidget *widget = new GuiWidget(this);
// declare a lambda
auto f = [widget] (QString str)
{
for (int i = 0; i < str.toInt(); ++i) {
// do some job
// ...
// job is done
// send progress data to mainwidget
QMetaObject::invokeMethod(widget, [widget, i] ()
{
widget->function(i);
}, Qt::QueuedConnection);
}
};
auto t1 = QtConcurrent::run(f, "100");