QThread更新QProgressDialog致GUI卡顿问题求助
问题描述
我开发了一个基于QMainWindow的应用,包含长耗时加载任务,因此创建了QProgressDialog和Worker线程(QThread),线程通过信号定期更新QProgressDialog。但遇到以下异常情况:
- 当用户将鼠标从进度对话框移至主窗口时,整个GUI(包括Windows系统的进度条动画)会出现卡顿;将鼠标移回进度对话框后,应用恢复正常。
- 采用
Qt::BlockingQueuedConnection连接线程信号时,GUI卡顿时线程也会停滞;若不使用阻塞连接,线程会继续运行,但GUI仍处于卡顿状态。 - 尝试了继承QThread和将Worker对象移至QThread两种实现方式,均出现该问题。
修改示例代码中的WORKER_QTHREAD宏定义为1或0,可切换两种线程实现方式。
环境信息
- 操作系统:Windows 10
- 开发环境:Visual Studio 2019 (16.11.19)
- Qt版本:5.14.2
- 代码理论兼容Linux,但未测试,暂不清楚Linux是否存在该问题。
复现代码
Classes.h
#pragma once #if _WIN32 #include <Windows.h> inline void sleep1() { Sleep(1000); } #else #include <unistd.h> inline void sleep1() { usleep(1000000); } #endif #include <QCheckBox> #include <QProgressDialog> #include <QMainWindow> #include <QString> #include <QThread> #include <QTimer> #define WORKER_QTHREAD 1 #if WORKER_QTHREAD class Work : public QThread #else class Work : public QObject #endif { Q_OBJECT public: /// @brief Constructor. /// @param pd - progress dialog to update explicit Work(QProgressDialog* pd = nullptr) { if (pd) { pd->setWindowModality(Qt::ApplicationModal); const Qt::ConnectionType conn = Qt::BlockingQueuedConnection; connect(this, &Work::progressRange, pd, &QProgressDialog::setRange, conn); connect(this, &Work::progressText, pd, &QProgressDialog::setLabelText, conn); connect(this, &Work::progressValue, pd, &QProgressDialog::setValue, conn); connect(pd, &QProgressDialog::canceled, this, &Work::cancel); } } virtual ~Work() {} void cancel() { m_canceled = true; } bool canceled() const { return m_canceled; } #if !WORKER_QTHREAD void start() { assert(!m_thread); m_thread = new QThread(); moveToThread(m_thread); connect(m_thread, &QThread::finished, m_thread, &QObject::deleteLater); connect(m_thread, &QThread::started, this, &Work::main); m_thread->start(); } #endif signals: #if !WORKER_QTHREAD void finished(); #endif void progressText(const QString& text); void progressRange(int32_t minimum, int32_t maximum); void progressValue(int32_t value); protected: virtual void run() = 0; private: #if !WORKER_QTHREAD void main() { run(); emit finished(); m_thread = nullptr; } QThread* m_thread { nullptr }; #endif bool m_canceled { false }; }; class Test : public Work { public: explicit Test(QProgressDialog* pd) : Work(pd) {} void run() { const int maximum = 100; emit progressText(""); emit progressRange(0, maximum); for (int i = 0; i < maximum; i++) { if (canceled()) break; emit progressValue(i + 1); sleep1(); } } }; class Main : public QMainWindow { public: Main() { setFixedSize(800, 600); setToolTip("Main window"); QCheckBox* cb = new QCheckBox("Move the mouse over this dialog\n" "Then move the mouse over the parent window, this window\n" "Try moving the mouse in circles around the dialog without going over the dialog\n" "The progress bar will stop moving\n" "The thread will also stop processing because of blocking queued connection\n" "Moving back over the dialog corrects the issue"); cb->setToolTip("Checkbox tooltip"); setCentralWidget(cb); } void showEvent(QShowEvent*) override { QTimer::singleShot(100, this, &Main::onStartup); } private: void onStartup() { QProgressDialog* pd = new QProgressDialog(this); Test* t = new Test(pd); connect(t, &Work::finished, pd, &QObject::deleteLater); connect(t, &Work::finished, t, &QObject::deleteLater); t->start(); } };
main.cpp
#include <QApplication> #include "Classes.h" int main(int argc, char *argv[]) { QApplication app(argc, argv); Main m; m.show(); return app.exec(); }
内容的提问来源于stack exchange,提问作者steveo225
相关产品推荐
相关产品推荐

