QT之多线程操作QprogressBar设置倒计时进度条

  • Post author:
  • Post category:其他




多线程的作用

我们在日常使用QT时经常会遇到使用多线程的情况,比如需要同时循环处理四个表的数据,如果只在主线程上处理,那么就需要等待四个循环的时间,这样就比较耗时,并且还会造成界面的阻塞造成卡顿,如果我们能同时开辟四个线程来处理,这样就相当于减少了等待的时间,提高效率。



如何创建线程

首先我们可以直接在头文件中添加一个类并继承QThread类

在这里插入图片描述

class MyThread : public QThread
{
    Q_OBJECT 
public:
    MyThread(MainWindow * My_ui);
    ~MyThread();
    void run() override;
    MainWindow * main_ui;
    int C_value;
    int C_time;
signals:
    void sendSignal();
public slots:
    void updateUi();
};

类里面的Q_OBJECT是一个宏,只要是继承了QOBJECT类,无论是直接子类还是间接子类,都需要在第一行添加Q_OBJECT宏,而Qthread类是继承自Qobject,并且只有加了这个宏才有使用信号槽的能力。

MyThread(MainWindow * My_ui);
~MyThread();

这两行分别是新类的构造函数和析构函数,我这里的构造函数给的变量是主窗口类,因为后面还会操作UI。析构函数是为了在该类销毁时运行的函数,一般里面会实现一些指针成员的释放,因为不及时释放的话容易造成内存泄露。

 void run() override;
    MainWindow * main_ui;
    int C_value;
    int C_time;

第一个函数为继承自Qthread的方法,需要进行重写,我们的实现逻辑就可以在run里面进行,override就代表该函数需要进行重写。后面三个就是创建了三个成员变量。

signals:
    void sendSignal();
public slots:
    void updateUi();

signals下的函数为信号函数,slots下为槽函数,信号函数顾名思义就是发出信号的作用,而槽函数则为接收信号而创建的,但是这时我们只是在类中创建了两个毫无联系的两个函数,如何把他们联系起来,这时我们就需要用到connect函数来连接他们俩个。

connect(this, SIGNAL(sendSignal()), this, SLOT(updateUi()));

当然这条语句我们需要写在合适的位置,一般我们希望在创建线程时就能把他们连接起来,而何时能实现,这我们就需要在新类中的构造函数中连接他们两个。实现的位置可以放在mainwindow.cpp中。

在这里插入图片描述

MyThread::MyThread(MainWindow * My_ui)
{
    main_ui = My_ui;
    connect(this, SIGNAL(sendSignal()), this, SLOT(updateUi()));

}
MyThread::~MyThread()
{
    this->quit();
}



创建线程设置倒计时进度条

这里我们需要创建两个控件,一个是按钮控件一个是进度条控件

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

我们右键按键转到槽后,在该跳转的槽函数下实现我们的逻辑。

void MainWindow::on_pushButton_clicked()
{
	ui->progressBar->setRange(0,30);//设置进度条的范围数值为0-30
	ui->progressBar->setFormat("还剩(%v)秒");
	MyThread *T = new MyThread(this);//创建一个进程,this代表当前窗口
	T->C_time = 30;//给子成员时间赋值给30
	T->start();//start()函数开始实现run函数
}

这边我们在run函数内重写

void MyThread::run()
{
    for(int i = C_time; i >= 0; i--)
    {
        C_value = i;
        emit(sendSignal());//emit用来发射信号
        QThread::msleep(1000);
        //每隔一秒发射一次信号,表示每隔一秒更新一次UI
    }
}

尽管我们可以创建多线程来同时处理好几个任务,但是子线程是不能直接操作UI的,只能通过一个中转,也就是我们在子类中创建了一个窗口成员(main_ui),而窗口类中有一个更改UI的槽函数(changeProgress),这样间接使用是允许的。

void MyThread::updateUi()
{
    main_ui->changeProgress(C_value);
}
void MainWindow::changeProgress(int value)
{
    if(value == 0)
    {
        ui->progressBar->setFormat("定时结束");
    }
        ui->progressBar->setValue(value);
}



完整代码

mainwindow.h

QT_BEGIN_NAMESPACE
namespace Ui { class MainWindow; }
QT_END_NAMESPACE
class MainWindow : public QMainWindow
{
    Q_OBJECT
public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();
    void changeProgress(int value);
private slots:
    void on_pushButton_clicked();
private:
    Ui::MainWindow *ui;
};
class MyThread : public QThread
{
    Q_OBJECT
public:
    MyThread(MainWindow * My_ui);
    ~MyThread();
    void run() override;
    MainWindow * main_ui;
    int C_value;
    int C_time;
signals:
    void sendSignal();
public slots:
    void updateUi();
};
#endif // MAINWINDOW_H

mainwindow.cpp

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
    , ui(new Ui::MainWindow)
{
    ui->setupUi(this);
    ui->progressBar->setValue(0);
    ui->progressBar->setFormat("");
}

MainWindow::~MainWindow()
{
    delete ui;
}
MyThread::MyThread(MainWindow * My_ui)
{
    main_ui = My_ui;
    connect(this, SIGNAL(sendSignal()), this, SLOT(updateUi()));

}
MyThread::~MyThread()
{
    this->quit();
}
void MyThread::run()
{
    for(int i = C_time; i >= 0; i--)
    {
        C_value = i;
        emit(sendSignal());
        QThread::msleep(1000);
    }
}
void MyThread::updateUi()
{
    main_ui->changeProgress(C_value);
}
void MainWindow::changeProgress(int value)
{
    if(value == 0)
    {
        ui->progressBar->setFormat("定时结束");
    }
        ui->progressBar->setValue(value);
}
void MainWindow::on_pushButton_clicked()
{
    ui->progressBar->setRange(0,30);
    ui->progressBar->setFormat("还剩(%v)秒");
    MyThread *T = new MyThread(this);
    T->C_time = 30;
    T->start();
}



最终效果

在这里插入图片描述



版权声明:本文为m0_49507996原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。