0%

QT进度条策略

版本:QT6.8

1、场景

        在做一个批处理数据工具时,采用QT做为界面框架,在实际作业生成过程中发现一个问题:在处理的数据量较大时,窗口会出现未响应,从而导致进度条状态无法更新。

2、分析

        窗口未响应,也就是窗口ui被阻塞了。QT的UI更新是单线程的,且只能在主线程中执行,而主线程中同时需要进行数据处理的业务逻辑,当数据量较大时,处理过程阻塞了UI更新的消息队列,从而导致了窗口未响应。

        解决思路,将数据处理业务逻辑单独放到一个子线程来处理,在子线程中发射信号来通知主线程更新进度条状态,主线程只进行UI操作,避免消息阻塞。

3、解决

  1. 创建一个处理数据的类Worker,继承QObject

  2. Worker 对象移到子线程中;

  3. 在子线程中进行数据处理业务逻辑,并发射信号回UI线程更新进度条;

代码示例

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
//数据处理类
class Worker : public QObject
{
Q_OBJECT
public slots:
void process()
{
emit progressIni(100);
for (int i = 0; i <= 100; ++i)
{
QThread::sleep(1); // 模拟数据处理
emit progressUpdated(i);
}
emit finished();
}

signals:
void progressIni(int value); //设置最大值并初始化
void progressUpdated(int value); //更新状态
void finished(); //线程结束标记
};

//主框架类
class QMainWindow : public QWidget
{
Q_OBJECT

public:
QMainWindow(QWidget *parent = nullptr);{}
~QMainWindow();{}
private slots:
void slotOK();

void updateProgress(int value);
void setProgressMaximum(int value);
void handleFinished();

private:
Ui::QMainWindow*m_pAppUi;

QThread* m_thread;
Worker* m_processor;
}

void QMainWindow::slotOK()
{
m_processor = new Worker();
m_thread = new QThread();

connect(m_thread, &QThread::started, m_processor, &Worker::process);
connect(m_processor, &Worker::progress, this, &QMainWindow::updateProgress);
connect(m_processor, &Worker::processfinished, this, &QMainWindow::handleFinished);
connect(m_processor, &Worker::progressIni, this, &QMainWindow::setProgressMaximum);
//线程结束后的资源释放操作由QT自动进行,不手动去释放了
connect(m_thread, &QThread::finished, m_processor, &QObject::deleteLater);
connect(m_thread, &QThread::finished, m_thread, &QObject::deleteLater);
//处理过程
m_thread->start();
}

void QMainWindow::handleFinished()
{
if (m_thread)
{
m_thread->quit();
m_thread->wait();
m_processor = nullptr;
m_thread = nullptr;
}
QMessageBox::information(this, "系统提示", "执行完成");
}

void GeoEntityCrackDlg::setProgressMaximum(int value)
{
m_pAppUi->progressBar1->setMaximum(value);
m_pAppUi->progressBar1->reset();
}
void GeoEntityCrackDlg::updateProgress(int value)
{
m_pAppUi->progressBar1->setValue(value);
}