在我的应用程序的一个单独组件中,我希望保持Qt依赖性,我正在使用std::thread
进行某些操作。我想在处理过程中对主应用程序进行更改。为此,我试图将一个函数(即:function<void(UpdateNode*)> nodeUpdatedCallback
)从我的应用程序传递给我的组件。
这个函数更新了UI,但由于我从另一个线程调用该函数,Qt说我无法从非主线程访问UI。
我已经看过许多文章通过使用QThread
和信号来解决这个问题,创建一个worker并将其移动到该线程。
由于我想使用std::thread
,是否可以使用std::thread
更新基于Qt的用户界面?
答案 0 :(得分:2)
当我在多线程环境中使用Qt,并且不想/不能使用惯用信号/插槽时,我将以下方法添加到我的对象中:
typedef std::function<void()> function_t;
void executeInObjectsThread(function_t const&);
private slots:
void executeInObjectsThreadSlot(function_t);
和定义:
void MyObj::executeInObjectsThread(function_t const& f)
{
QMetaObject::invokeMethod(
this,
"executeInObjectsThreadSlot",
Qt::QueuedConnection,
Q_ARG(function_t,f)
);
}
然后在你的另一个帖子中,你只需要打电话
foo->executeInObjectsThread([=]{
foo->addWidget(new QWidget(foo));
// ...
foo->editBox->setText(QString::number(currentResult));
foo->progressBar->setValue(n);
});
答案 1 :(得分:1)
基本上你不应该从另一个线程修改任何GUI相关的东西。这有一个很好的理由:GUI依赖于非线程安全的事件循环。你开始玩它,你会因竞争条件而得到不确定的行为。感谢Qt保护你免受搞乱!
但是,您的问题的解决方案非常简单。我在你的情况下做的是我定义一个线程修改的公共变量。所以我使用QTimer
来检查线程是否已完成其工作。要知道线程是否已完成,您可以使用将在计算结束时设置的std::atomic<bool>
标志(或使用std::promise/future
,我更喜欢)。然后,GUI将只读取主线程的(也是线程安全的)结果并显示它们。这是100%安全的。
最近我和Neblio这样做了。 Check out my code there表示在另一个线程中运行的自动更新程序,并在GUI上显示结果。
答案 2 :(得分:1)
Qt确实使用信号/插槽机制。你只提到信号部分,但这里的插槽也非常重要。一个槽位于一个对象中,如果该对象是一个具有线程关联性的Qt对象,则该槽将在该线程中执行。即使信号来自另一个线程,这也成立。
当插槽所有者为QWindow
或类似于UI线程关联的东西时,这尤其有用。它确保UI代码在正确的线程中运行。几乎可以肯定,UI线程是应用程序的main()
线程。
所以你仍然可以从std::thread
获得信号。它不会导致插槽在同一std::thread
中运行。