1 QProgressDialog
概述
QProgressDialog
类提供耗时操作的进度条。
进度对话框用于向用户指示操作将花费多长时间,并演示应用程序没有冻结。此外,QPorgressDialog
还可以给用户一个中止操作的机会。
进度对话框的一个常见问题是很难知道何时使用它们;操作在不同的硬件上花费不同的时间。QProgressDialog
为这个问题提供了一个解决方案:它估计操作将花费的时间(基于步骤的时间),并且仅在估计超过minimumDuration()
(默认为4
秒)时才显示它自己。
使用setMinimum()
和setMaximum()
或构造函数设置操作中的“steps”数,并在操作进行时调用setValue()
。steps
数可以任意选择。它可以是复制的文件数、接收的字节数、通过算法主循环的迭代次数,或者其他合适的单位。进度从setMinimum()
设置的值开始,当使用setMaximum()
设置的值作为参数调用setValue()
时,进度对话框显示操作已经完成。
在操作结束时,对话框会自动重置并隐藏自己。使用setAutoReset()
和setAutoClose()
来改变这种行为。
注意,如果设置了一个新的最大值(使用setMaximum()
或setRange()
),它等于你的当前值(),无论如何对话框都不会关闭。
QProgressDialog progress;
progress.setMaximun(100);
Progress.setValue(100);
以上代码,对话框不会自动隐藏。
QProgressDialog
有两种使用方式:模态和非模态。
与非模态QProgressDialog
相比,模态QProgressDialog
对于程序员来说更容易使用。在循环中执行操作,每隔一段时间调用setValue()
,并使用wasCanceled()
检查是否取消。
例如:
QProgressDialog progress("复制文件...", "中止", 0, numFiles, this);
progress.setWindowModality(Qt::WindowModal);
for (int i = 0; i < numFiles; i++) {
progress.setValue(i);
if (progress.wasCanceled())
break;
// 开始复制
// ......
}
// 复制完成,将最大值设置给当前值,对话框自动隐藏,关闭
progress.setValue(numFiles);
2 QProgressDialog常用函数
2.1 构造函数:
- QProgressDialog(QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()):创建一个默认的进度对话框,parent是对话框的父部件,f是对话框的窗口标志。
- QProgressDialog(const QString &labelText, const QString &cancelButtonText, int minimum, int maximum, QWidget *parent = Q_NULLPTR, Qt::WindowFlags f = Qt::WindowFlags()):创建一个带有文本标签、取消按钮和进度范围的进度对话框。labelText是标签的文本,cancelButtonText是取消按钮的文本,minimum和maximum指定了进度的范围。
2.2 成员函数:
- void cancel():重置进度对话框,将wasCanceled()标记为true,直到进度对话框被重置。进度对话框将隐藏起来。
- void canceled():在点击取消按钮时发射的信号,默认与cancel()槽连接。
- void open(QObject *receiver, const char *member):打开对话框,并将其canceled()信号连接到receiver对象的member槽上。
- void reset():重置进度对话框,如果autoClose()为true,则对话框将隐藏。
- void setBar(QProgressBar *bar):设置进度条部件。
- void setCancelButton(QPushButton *cancelButton):设置取消按钮部件。
- void setCancelButtonText(const QString &cancelButtonText):设置取消按钮的文本。
- void setLabel(QLabel *label):设置标签部件。
- void setRange(int minimum, int maximum):设置进度范围。
- QSize sizeHint() const:返回适合对话框内容的大小。
2.3 常用方法示例代码
CustomProgress::CustomProgress(QWidget *parent) : QProgressDialog(parent)
{
// 设置窗体Flags, 对话框 | 只有关闭按钮,无问号
this->setWindowFlags(Qt::Dialog | Qt::WindowCloseButtonHint);
// 设置取消按钮文本
this->setCancelButtonText("取消");
// 设置进度条区间,等同分别设置最小值 和 最大值
setRange(0, 100);
// 设置最小值
setMinimum(0);
// 设置最大值
setMaximum(100);
// 设置当前值
setValue(0);
// 设置文本,一般在进度条上方显示
setLabelText("helloworld");
// 设置自动关闭,当reset()时,对话框自动关闭,默认为true
setAutoClose(true);
// 设置自动重置,当reset()或当前值 == 最大值时,重置
setAutoReset(true);
connect(this, &CustomProgress::canceled, this, &CustomProgress::cancel);
// 设置对话框窗体标题
this->setWindowTitle("等待...");
}
3 线程Qthread
当在主线程里,进行耗时操作,然后加载进度对话框时,会发现,对话框进度条会卡死不动,然后耗时操作结束,对话框进度条直接关闭,界面感官不友好。
因此需要将耗时操作放到线程内操作,主线程就进行进度显示。界面也不会卡死。
QThread类
提供了一种独立于平台的方式来管理线程。
QThread
对象管理程序中的一个控制线程。QThreads
在run()
中开始执行。默认情况下,run()
通过调用exec()
启动事件循环,并在线程内运行Qt事件循环。
此外,还可以通过使用QObject::moveToThread()
将工作对象移动到线程中来使用它们。
下面是四种线程使用方式与进度框相结合,模拟处理耗时操作,主界面显示进度。
3.1 继承QThread
,重写run()
方法
.h
class C_Thread : public QThread
{
Q_OBJECT
public:
explicit C_Thread(int nMax, QObject *parent = nullptr);
virtual void run() override;
signals:
void emit_sendValue(int nValue);
private:
int m_nMax;
};
.cpp
#include "Thread.h"
C_Thread::C_Thread(int nMax, QObject *parent) : QThread(parent), m_nMax(nMax)
{
}
void C_Thread::run()
{
int i = 0;
while (i < m_nMax) {
msleep(100);
++i;
emit emit_sendValue(i);
}
}
当进行start()
时,自动调用run()
,每过100ms,发送一个数据,主界面进行显示
3.2 继承QObject
,之后添加到线程moveToThread()
,使用信号和槽方式
需要将进行耗时操作的类,移动到线程中,之后以信号和槽的方式和进度框进行交互
.h
class C_ThreadObject : public QObject
{
Q_OBJECT
public:
explicit C_ThreadObject(int nMax, QObject *parent = nullptr);
signals:
void emit_sendValue(int nValue);
public slots:
void slot_dealValue();
private:
int m_nMax;
};
.cpp
C_ThreadObject::C_ThreadObject(int nMax, QObject *parent) : QObject(parent), m_nMax(nMax)
{
}
void C_ThreadObject::slot_dealValue()
{
int i = 0;
while (i < m_nMax) {
QThread::msleep(100);
++i;
emit emit_sendValue(i);
}
}
3.3 继承QRunnable
重写run()
,然后通过线程池调用
.h
class C_ThreadRunnable :public QObject, public QRunnable
{
Q_OBJECT
public:
explicit C_ThreadRunnable(int nMax);
signals:
void emit_sendValue(int nValue);
public slots:
protected:
virtual void run() override;
private:
int m_nMax;
};
.cpp
C_ThreadRunnable::C_ThreadRunnable(int nMax) : m_nMax(nMax)
{
}
void C_ThreadRunnable::run()
{
int i = 0;
while (i < m_nMax) {
QThread::msleep(100);
++i;
emit emit_sendValue(i);
}
}
3.4 使用QtConcurrent
模块
Qt Concurrent模块扩展了Qt Core模块中的基本线程支持,简化了可以在所有可用CPU内核上并行执行的代码开发。
.h
void MainWindow::dealValue()
{
int i = 0;
while (i < m_nMax) {
QThread::msleep(100);
++i;
emit emit_sendValue(i);
}
}
.cpp
QtConcurrent::run(this, &MainWindow::dealValue);
3.5 主线程调用
创建各个线程对象,然后进行模拟耗时操作,进度框显示进度
如果在构造中new过QProgressDialog对象,默认4秒后,会自动显示,可以调用其close()
方法,不用显示。
.h
class MainWindow : public QMainWindow
{
Q_OBJECT
public:
explicit MainWindow(QWidget *parent = nullptr);
~MainWindow();
void dealValue();
signals:
void emit_start();
void emit_sendValue(int nValue);
private slots:
void on_btn_TimeConsumingOperation_clicked();
private:
Ui::MainWindow *ui;
int m_nMax;
C_DlgProgress* m_pDlgProgress;
C_Thread* m_pTread;
C_ThreadRunnable* m_pThreadRunnable;
C_ThreadObject* m_pThreadObject;
QThread* m_pThreadUsedObject;
};
.cpp
#include "mainwindow.h"
#include "ui_mainwindow.h"
#include <QThreadPool>
#include <QtConcurrent>
#include <QDebug>
MainWindow::MainWindow(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::MainWindow)
{
ui->setupUi(this);
m_nMax = 20;
m_pDlgProgress = new C_DlgProgress(this);
m_pDlgProgress->setRange(0, m_nMax);
// 1. 继承QThread
m_pTread = new C_Thread(m_nMax, this);
connect(m_pTread, &C_Thread::emit_sendValue, this, [=](int nValue){
m_pDlgProgress->setValue(nValue);
});
// 2. 继承QRunnable
m_pThreadRunnable = new C_ThreadRunnable(m_nMax);
connect(m_pThreadRunnable, &C_ThreadRunnable::emit_sendValue, this, [=](int nValue){
m_pDlgProgress->setValue(nValue);
});
// 3. 继承QObject
m_pThreadObject = new C_ThreadObject(m_nMax);
connect(this, &MainWindow::emit_start, m_pThreadObject, &C_ThreadObject::slot_dealValue);
connect(m_pThreadObject, &C_ThreadObject::emit_sendValue, this, [=](int nValue){
m_pDlgProgress->setValue(nValue);
});
m_pThreadUsedObject = new QThread(this);
m_pThreadObject->moveToThread(m_pThreadUsedObject);
m_pThreadUsedObject->start();
// 0. 在主线程处理耗时操作
connect(this, &MainWindow::emit_sendValue, this, [=](int nValue){
m_pDlgProgress->setValue(nValue);
});
}
MainWindow::~MainWindow()
{
if(m_pThreadUsedObject)
{
m_pThreadUsedObject->quit();
m_pThreadUsedObject->wait();
}
delete ui;
}
void MainWindow::dealValue()
{
int i = 0;
while (i < m_nMax) {
QThread::msleep(100);
++i;
emit emit_sendValue(i);
}
}
void MainWindow::on_btn_TimeConsumingOperation_clicked()
{
m_pDlgProgress->show();
// 0. 在主线程模拟处理耗时操作,界面卡死
// int i = 0;
// while (i < m_nMax) {
// QThread::msleep(100);
// ++i;
// emit emit_sendValue(i);
// }
/*********** 使用哪个,打开哪个注释 ***********/
// 1. 继承QThread
// m_pTread->start();
// 2. 继承QRunnable
// QThreadPool::globalInstance()->start(m_pThreadRunnable);
// 3. 继承QObject
// emit emit_start();
// 4. 使用QtConcurrent模块
// QtConcurrent::run(this, &MainWindow::dealValue);
}
3.6 结果
主界面显示:
点击耗时操作
:
当进度走完,进度框关闭。
4 完整示例连接
链接: https://download.csdn.net/download/MrHHHHHH/88692241?spm=1001.2014.3001.5501