在另一个 QThread 上运行成员方法时,无法将事件发送到不同线程拥有的对象
Cannot send events to objects owned by a different thread while runing a member method on another QThread
我需要 运行 我的 MainWindow class 中的一个方法,在不同的线程中,因为它是一个耗时长的过程。
这是我试过的:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
initGui(ui);
// Create background worker thread
backgroundWorker = QThread::create([this] {
backgroundMethod();
});
// Define when finished with work
connect(backgroundWorker, &QThread::finished, [this] () {
qDebug() << "Background method has finished";
// Stop movie
ui->lblLoading->movie()->stop();
// go to next screen
ui->tabbarMainWidget->tabBar()->setCurrentIndex(1);
//show backup icon files
if(filesToBackup.size() > 0) {
qDebug() << "There are files to backup!";
ui->lblInfoImage->show();
}
});
// Start worker thread
backgroundWorker->start();
}
backgroundMethod
void MainWindow::backgroundMethod() {
for (int i = 0; i < 10; i++) {
qDebug() << "Hello World";
}
}
我省略了很多没有必要的代码。基本逻辑如下:
开始新线程
运行 backgroundMethod()
直到完成,同时有 UI 空闲时间用于其他工作。
当 backgroundMethod()
完成后,QThread
应该发出 finished() 信号。
我在 backgroundWorker
线程的 finished()
和 lambda 之间设置了一个连接到 运行 更多代码。
问题:
Background method has finished
QObject::killTimer: Timers cannot be stopped from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x2801d950. Receiver 'lblInfoImage'
(of type 'QLabel') was created in thread 0x0x2688c4b0", file
kernel\qcoreapplication.cpp, line 578 04:11:28: The program has
unexpectedly finished.
简而言之,我正在 backgroundWorker
线程上访问 lblInfoImage
。我知道使用 signal/slot mechanism 应该可以解决这个问题,我的使用是正确的。
我不确定为什么会这样,我需要一些帮助来理解我做了什么导致了这个问题以及我该如何解决它
问题很简单:您在非 UI 线程上执行 UI 代码,这在 Qt 中是严格禁止的(以及许多其他跨不同语言的 UI 框架)。发生这种情况是因为您连接错误:
connect(backgroundWorker, &QThread::finished, [this] () {
...
});
那个连接意味着:每当QThread
发出一个finished
信号运行这个函数。问题是,它将 运行 发出信号上下文中的函数是另一个线程,而不是 backgroundWorker
所在的线程。所以你必须提供 UI 线程上下文来接收这个信号:
connect(backgroundWorker, &QThread::finished, this, [this] () {
...
});
现在提供的函数将在 UI 线程 (this
) 的上下文中执行。
我需要 运行 我的 MainWindow class 中的一个方法,在不同的线程中,因为它是一个耗时长的过程。
这是我试过的:
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
initGui(ui);
// Create background worker thread
backgroundWorker = QThread::create([this] {
backgroundMethod();
});
// Define when finished with work
connect(backgroundWorker, &QThread::finished, [this] () {
qDebug() << "Background method has finished";
// Stop movie
ui->lblLoading->movie()->stop();
// go to next screen
ui->tabbarMainWidget->tabBar()->setCurrentIndex(1);
//show backup icon files
if(filesToBackup.size() > 0) {
qDebug() << "There are files to backup!";
ui->lblInfoImage->show();
}
});
// Start worker thread
backgroundWorker->start();
}
backgroundMethod
void MainWindow::backgroundMethod() {
for (int i = 0; i < 10; i++) {
qDebug() << "Hello World";
}
}
我省略了很多没有必要的代码。基本逻辑如下:
- 开始新线程
运行
backgroundMethod()
直到完成,同时有 UI 空闲时间用于其他工作。当
backgroundMethod()
完成后,QThread
应该发出 finished() 信号。我在
backgroundWorker
线程的finished()
和 lambda 之间设置了一个连接到 运行 更多代码。
问题:
Background method has finished
QObject::killTimer: Timers cannot be stopped from another thread
ASSERT failure in QCoreApplication::sendEvent: "Cannot send events to objects owned by a different thread. Current thread 0x0x2801d950. Receiver 'lblInfoImage' (of type 'QLabel') was created in thread 0x0x2688c4b0", file kernel\qcoreapplication.cpp, line 578 04:11:28: The program has unexpectedly finished.
简而言之,我正在 backgroundWorker
线程上访问 lblInfoImage
。我知道使用 signal/slot mechanism 应该可以解决这个问题,我的使用是正确的。
我不确定为什么会这样,我需要一些帮助来理解我做了什么导致了这个问题以及我该如何解决它
问题很简单:您在非 UI 线程上执行 UI 代码,这在 Qt 中是严格禁止的(以及许多其他跨不同语言的 UI 框架)。发生这种情况是因为您连接错误:
connect(backgroundWorker, &QThread::finished, [this] () {
...
});
那个连接意味着:每当QThread
发出一个finished
信号运行这个函数。问题是,它将 运行 发出信号上下文中的函数是另一个线程,而不是 backgroundWorker
所在的线程。所以你必须提供 UI 线程上下文来接收这个信号:
connect(backgroundWorker, &QThread::finished, this, [this] () {
...
});
现在提供的函数将在 UI 线程 (this
) 的上下文中执行。