我有一個工人需要完成任意阻塞任務
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();
}
當我運行程式時,我只是得到一個旋轉的滑鼠圈,并且視窗內容直到 10 秒后才加載(當作業人員完成時)。為什么會這樣?我需要做什么才能Worker::start在后臺運行而不影響 GUI?
PS我使用的是 Qt 6.2.2 和 Windows 11,但我非常懷疑這與這個問題有什么關系。
uj5u.com熱心網友回復:
簡單地:
class MainWindow : public QWidget
{
Q_OBJECT;
public:
explicit MainWindow(QWidget* parent = nullptr) : QWidget(parent)
{
QThread* t = new QThread(); // delete this
Worker* w = new Worker(); // delete this
w->moveToThread(t);
this->connect(
t, &QThread::started,
w, &Worker::start
);
this->connect(
t, &QThread::finished,
t, &QThread::deleteLater
);
t->start();
}
};
它給出了一個合理的 解釋。
uj5u.com熱心網友回復:
如果你檢查你的輸出,你很可能會發現這樣一行:
QObject::moveToThread: Cannot move objects with a parent
為了證明你不能,只需添加一些除錯行:
QThread* t = new QThread(this);
Worker* w = new Worker( this);
w->moveToThread(t);
qDebug() << "CURRENT: " << QThread::currentThread();
qDebug() << "WORKER : " << w->thread();
Worker的執行緒仍然是當前執行緒,試圖將其移入t...
我建議將兩個物件(QThread 和 Worker)都設為 MainWindow 類的私有成員:沒有理由使用指標,這里:
class MainWindow : public QWidget
{
Q_OBJECT;
QThread _thread;
Worker _worker;
public:
explicit MainWindow(QWidget* parent = nullptr) : QWidget(parent)
{
_worker.moveToThread(t);
connect(
&_thread, &QThread::started,
&_worker, &Worker::start
);
_thread.start();
}
};
uj5u.com熱心網友回復:
問題是工人實際上并沒有移動到執行緒(不是警告寫入控制臺嗎?我敢打賭。),因為它的父級,即MainWindow實體仍在 GUI 執行緒中。
移動到執行緒時,您只能通過移動最頂層的父級來移動物件的整個層次結構。您不能讓父級與其子級處于不同的執行緒中。
您應該創建沒有父級的工人。
Worker* w = new Worker();
當然,您還應該finished()為您的Worker課程添加一些信號。
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
);
否則你的執行緒的偶數回圈不會結束,worker 也不會被洗掉。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qita/407438.html
標籤:
