QT multi-threading combat

presentation of needs

The window itself is an infinite loop, and any time-consuming operation performed in such an infinite loop will cause the program to crash. So multithreading is necessary for window programming.

pushButtonFor example, drag a sum in the window lineEdit, change pushButtonthe name to pbStart, and then bind a function to it, create an infinite loop in the function, and let the content in the infinite loop be output to it in real time lineEdit.

Next, design a logic, when clicked pbStart, start to execute the infinite loop, and at the same time the button content becomes ;Stop when the button content is , click the button to stop executing the infinite loop.Stop

Therefore, you need to design a member variable to control whether the loop continues to execute, MainWindowand add private members to the header file of bool flag. added in the cppfile flag = true.

Then go to the design interface, right pbStartbutton -> 转到槽-> clicked(). which MainWindowadds a on_pbStart_clickedfunction called to it, filled with the contents of

void MainWindow::on_pbStart_clicked()
{
    
    
    int i= 0;
    bool flag = QString::compare(ui->pbStart->text(),"start");
    if(flag)
        ui->pbStart->setText("stop");
    while(flag){
    
    
        i++;
        ui->lineEdit->setText(QString::number(i));
    }
}

After the result runs, it really falls into an infinite loop, and the program cannot respond. The most excessive thing is that there is lineEditno change. At this time, multi-threading must be considered.

insert image description here

Multithreading

QThreadIt is the most basic thread class in Qt, and each instance can control a thread. The traditional calling method is to create a new inherited QThreadclass, and then write the time-consuming task into the runfunction. Since QT4.4, it is recommended moveToThread()to call multithreading through functions.

First create a new class, Ctrl+ in the project, select -> -> Nin the pop-up dialog box , define the name of the class as , and select it .Files and ClassesC/C++C++ ClassThTestQObject

Make the class inherit QObjectand change the header file ThTestto

class ThTest : public QObject
{
    
    
    Q_OBJECT
public:
    ThTest();
    ~ThTest();
    void Func(void);
};

Correspondingly, cppthe content of the file is

#include "thtest.h"
#include <QDebug>
#include <QThread>

ThTest::ThTest(){
    
    }
ThTest::~ThTest(){
    
    }

void ThTest::Func()
{
    
    
    int NowNum = 0;
    while(true){
    
    
        NowNum++;
        qDebug()<<NowNum<<QThread::currentThreadId();
    }
}

Then change mainwindowthe code in its header file as follows

#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QThread>
#include <QObject>
#include <QDebug>
#include "thtest.h"

QT_BEGIN_NAMESPACE
namespace Ui {
    
     class MainWindow; }
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    
    
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    void ToThread(); // 信号
private slots:
    void on_pbStart_clicked();
private:
    Ui::MainWindow *ui;
    QThread *qThTest;
    ThTest *th1;
};
#endif

Then change the function cppin the file toon_pbStart_clicked

void MainWindow::on_pbStart_clicked()
{
    
    
    qThTest = new QThread;
    th1 = new ThTest;
    connect(this,&MainWindow::ToThread,th1,&ThTest::Func);
    th1->moveToThread(qThTest);
    qThTest->start();
    emit ToThread();
}

Among them, connectthe ToThreadfunction and ThTestthe Funcfunction in are bound together. ToThreadThat is to say, when the signal is emitted here , this function Th1will be executed .Func

Therefore, when the thread starts, by emitsending a ToThreadsignal, the number will continue to be output on the command line, and the window will not die.

At this point, in fact, some multi-threaded tasks can be processed, but the incremental NowNumdisplay cannot be displayed on the main window, which makes it lineEditlook a bit tasteless. In order to display the increasing number on the window, the next thing that needs to be done is the communication between the threads.

Inter-thread communication

Thanks to Qt's signal and slot mechanism, communication between multiple threads is not complicated. Even, it can be considered in a broad sense that emit ToThread()it is also a process of inter-thread communication.

So just on_pbStart_clickedadd a line in

connect(th1,SIGNAL(sendInt(int)),this,SLOT(getInt(int)));

It means to th1transmit one sendInt(int)and thisreceive one getInt(int). The names of these two functions do not matter, but they must not contain formal parameters, but only the data types of the formal parameters.

Next, in thtest.hthe add sendInt,

signals:
    void sendInt(int);

and change its Funcfunction

void ThTest::Func(){
    
    
    int NowNum = 0;
    while(true){
    
    
        QThread::sleep(1);
        emit sendInt(NowNum++);
    }
}

Finally, mainwindow.hadd in

private slots:
    void getInt(int);

and cppin the file

void MainWindow::getInt(int num){
    
    
    ui->lineEdit->setText(QString::number(num));
}

In this way, after clicking start, you can see lineEditthe change of the upper number.

insert image description here

Terminate multithreading

Finally, back to the original requirement, click startto start, then the button becomes stop, click stopand then stop.

Considering that it terminateis not safe, the final whilemethod is used to exit the infinite loop. The way is ThTestto add a boolmember of the type runningin the header file

public:
    bool running=true;

whileand change the loop in the source file

void ThTest::Func(){
    
    
    int NowNum = 0;
    while(running){
    
    
        emit sendInt(NowNum++);
        QThread::sleep(1);
    }
}

Last Reviewon_pbStart_clicked

void MainWindow::on_pbStart_clicked()
{
    
    

    bool flag = QString::compare(ui->pbStart->text(),"stop");
    qDebug()<<ui->pbStart->text();
    th1->running = flag;
    ui->pbStart->setText(flag?"stop":"start");
    if(flag){
    
    
        th1->moveToThread(qThTest);
        qThTest->start();
        emit ToThread();
    }
    else
        ui->lineEdit->setText("0");
}

And remove the th1wait for initialization process

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent), ui(new Ui::MainWindow)
{
    
    
    ui->setupUi(this);
    qThTest = new QThread;
    th1 = new ThTest;
    connect(th1,SIGNAL(sendInt(int)),this,SLOT(getInt(int)));
    connect(this,&MainWindow::ToThread,th1,&ThTest::Func);
}

As a result, the thread terminated

insert image description here

Guess you like

Origin blog.csdn.net/m0_37816922/article/details/124298084