Qt GUI 与 QThread 中的 worker 一起挂起
Qt GUI hanging with worker in a QThread
我有一个工人需要完成一个任意阻塞任务
class Worker : public QObject
{
Q_OBJECT;
public:
using QObject::QObject;
public slots:
void start()
{
for (int i = 0; i < 10; i++)
{
qDebug("I'm doing work...");
Sleep(1000);
}
}
};
在我的 MainWindow
构造函数中,我这样开始任务:
class MainWindow : public QWidget
{
Q_OBJECT;
public:
explicit MainWindow(QWidget* parent = nullptr) : QWidget(parent)
{
QThread* t = new QThread(this);
Worker* w = new Worker(this);
w->moveToThread(t);
this->connect(
t, &QThread::started,
w, &Worker::start
);
this->connect(
t, &QThread::finished,
t, &QThread::deleteLater
);
t->start();
}
};
我的切入点:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MainWindow mainWindow{};
mainWindow.show();
return app.exec();
}
当我 运行 程序时,我只是得到一个旋转的鼠标圈,并且 window 内容直到 10 秒后才加载(当工作人员完成时)。为什么会这样?我需要做什么才能使 Worker::start
在后台 运行 而不影响 GUI?
P.S. 我正在使用 Qt 6.2.2 和 Windows 11,但我非常怀疑这与此问题有任何关系。
问题是 worker 实际上并没有移动到线程(不是写入控制台的警告吗?我敢打赌是。),因为它的父实例,即 MainWindow
实例仍在 GUI 中线程。
移动到线程时,只能通过移动最顶层的父对象来移动对象的整个层次结构。您不能让父线程与其子线程处于不同的线程中。
您应该创建没有父级的工人。
Worker* w = new Worker();
当然你也应该在你的 Worker
class.
中添加一些 finished()
信号
class Worker : public QObject
{
Q_OBJECT;
public:
using QObject::QObject;
void start()
{
for (int i = 0; i < 10; i++)
{
qDebug("I'm doing work...");
Sleep(1000);
}
emit finished();
}
signals:
void finished();
};
并添加这些连接:
this->connect(
w, &Worker::finished,
t, &QThread::quit
);
this->connect(
t, &QThread::finished,
w, &Worker::deleteLater
);
否则你线程的even循环不会结束,worker也不会被删除
我有一个工人需要完成一个任意阻塞任务
class Worker : public QObject
{
Q_OBJECT;
public:
using QObject::QObject;
public slots:
void start()
{
for (int i = 0; i < 10; i++)
{
qDebug("I'm doing work...");
Sleep(1000);
}
}
};
在我的 MainWindow
构造函数中,我这样开始任务:
class MainWindow : public QWidget
{
Q_OBJECT;
public:
explicit MainWindow(QWidget* parent = nullptr) : QWidget(parent)
{
QThread* t = new QThread(this);
Worker* w = new Worker(this);
w->moveToThread(t);
this->connect(
t, &QThread::started,
w, &Worker::start
);
this->connect(
t, &QThread::finished,
t, &QThread::deleteLater
);
t->start();
}
};
我的切入点:
int main(int argc, char** argv)
{
QApplication app(argc, argv);
MainWindow mainWindow{};
mainWindow.show();
return app.exec();
}
当我 运行 程序时,我只是得到一个旋转的鼠标圈,并且 window 内容直到 10 秒后才加载(当工作人员完成时)。为什么会这样?我需要做什么才能使 Worker::start
在后台 运行 而不影响 GUI?
P.S. 我正在使用 Qt 6.2.2 和 Windows 11,但我非常怀疑这与此问题有任何关系。
问题是 worker 实际上并没有移动到线程(不是写入控制台的警告吗?我敢打赌是。),因为它的父实例,即 MainWindow
实例仍在 GUI 中线程。
移动到线程时,只能通过移动最顶层的父对象来移动对象的整个层次结构。您不能让父线程与其子线程处于不同的线程中。
您应该创建没有父级的工人。
Worker* w = new Worker();
当然你也应该在你的 Worker
class.
finished()
信号
class Worker : public QObject
{
Q_OBJECT;
public:
using QObject::QObject;
void start()
{
for (int i = 0; i < 10; i++)
{
qDebug("I'm doing work...");
Sleep(1000);
}
emit finished();
}
signals:
void finished();
};
并添加这些连接:
this->connect(
w, &Worker::finished,
t, &QThread::quit
);
this->connect(
t, &QThread::finished,
w, &Worker::deleteLater
);
否则你线程的even循环不会结束,worker也不会被删除