利用Qt訊號槽和std::function將任務放在主執行緒(GUI執行緒)執行
阿新 • • 發佈:2022-05-09
- 宣告一個新增任務介面,訊號和槽函式各兩個(返回型別void和非void)。新增任務介面的引數為std::function型別。訊號與槽函式的第一個引數是std::function型別的任務,第二個引數則為任務的返回值。
class TestQtMainThread : public QWidget { Q_OBJECT public: TestQtMainThread(QWidget* parent = Q_NULLPTR); template <typename T> T AppendTask(const std::function<T()>& task); signals: void SIGAppendTask(const std::function<QVariant()>& task, QVariant& ret); void SIGAppendTask(const std::function<void()>& task); private slots: void ONAppendTask(const std::function<QVariant()>& task, QVariant& ret); void ONAppendTask(const std::function<void()>& task); private: Ui::TestQtMainThreadClass ui; };
- 使用Qt::BlockingQueuedConnection方式連線訊號與槽函式
connect(this, qOverload<const std::function<QVariant()> &, QVariant &>( &TestQtMainThread::SIGAppendTask), this, qOverload<const std::function<QVariant()> &, QVariant &>( &TestQtMainThread::ONAppendTask), Qt::BlockingQueuedConnection); connect( this, qOverload<const std::function<void()> &>( &TestQtMainThread::SIGAppendTask), this, qOverload<const std::function<void()> &>(&TestQtMainThread::ONAppendTask), Qt::BlockingQueuedConnection);
- 槽函式定義
void TestQtMainThread::ONAppendTask(const std::function<QVariant()> &task,
QVariant &ret) {
ret = task();
}
void TestQtMainThread::ONAppendTask(const std::function<void()> &task) {
task();
}
- 介面定義
template <typename T> inline T TestQtMainThread::AppendTask(const std::function<T()>& task) { // 訊號槽無法對沒特化的tempalte進行connect,使用QVariant轉換 // 轉換包括:1.使用lambda包裹task轉換其返回型別;2.轉換引數型別 QVariant ret; // 避免BlockingQueuedConnection死鎖 // this->thread() == QCoreApplication::instance()->thread() if (QThread::currentThread() == this->thread()) { ONAppendTask([&]() { return QVariant::fromValue<T>(task()); }, ret); } else { emit SIGAppendTask([&]() { return QVariant::fromValue<T>(task()); }, ret); } return ret.value<T>(); } // void特化版 template <> inline void TestQtMainThread::AppendTask(const std::function<void()>& task) { if (QThread::currentThread() == this->thread()) { ONAppendTask(task); } else { emit SIGAppendTask(task); } }
- 使用
// WorkerThread是QThread子類,此段函式在非主執行緒執行
void WorkerThread::run() {
auto result = main_thread_->AppendTask<QString>([]() {
if (QThread::currentThread() != QCoreApplication::instance()->thread()) {
return "error!";
}
return "ok!";
});
qDebug() << result;
// QWidget::move(...),此函式不允許在非主執行緒呼叫
main_thread_->AppendTask<void>([&]() { main_thread_->move({0, 0}); });
}
覆蓋QWidget::move(...),非子執行緒可直接呼叫TestQtMainThread::move(...)
void TestQtMainThread::move(const QPoint &pos) {
this->AppendTask<void>([&] { this->QWidget::move(pos); });
}