Article directory
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.
pushButton
For example, drag a sum in the window lineEdit
, change pushButton
the 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, MainWindow
and add private members to the header file of bool flag
. added in the cpp
file flag = true
.
Then go to the design interface, right pbStart
button -> 转到槽
-> clicked()
. which MainWindow
adds a on_pbStart_clicked
function 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 lineEdit
no change. At this time, multi-threading must be considered.
Multithreading
QThread
It 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 QThread
class, and then write the time-consuming task into the run
function. Since QT4.4, it is recommended moveToThread()
to call multithreading through functions.
First create a new class, Ctrl
+ in the project, select -> -> N
in the pop-up dialog box , define the name of the class as , and select it .Files and Classes
C/C++
C++ Class
ThTest
QObject
Make the class inherit QObject
and change the header file ThTest
to
class ThTest : public QObject
{
Q_OBJECT
public:
ThTest();
~ThTest();
void Func(void);
};
Correspondingly, cpp
the 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 mainwindow
the 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 cpp
in 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, connect
the ToThread
function and ThTest
the Func
function in are bound together. ToThread
That is to say, when the signal is emitted here , this function Th1
will be executed .Func
Therefore, when the thread starts, by emit
sending a ToThread
signal, 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 NowNum
display cannot be displayed on the main window, which makes it lineEdit
look 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_clicked
add a line in
connect(th1,SIGNAL(sendInt(int)),this,SLOT(getInt(int)));
It means to th1
transmit one sendInt(int)
and this
receive 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.h
the add sendInt
,
signals:
void sendInt(int);
and change its Func
function
void ThTest::Func(){
int NowNum = 0;
while(true){
QThread::sleep(1);
emit sendInt(NowNum++);
}
}
Finally, mainwindow.h
add in
private slots:
void getInt(int);
and cpp
in the file
void MainWindow::getInt(int num){
ui->lineEdit->setText(QString::number(num));
}
In this way, after clicking start
, you can see lineEdit
the change of the upper number.
Terminate multithreading
Finally, back to the original requirement, click start
to start, then the button becomes stop
, click stop
and then stop.
Considering that it terminate
is not safe, the final while
method is used to exit the infinite loop. The way is ThTest
to add a bool
member of the type running
in the header file
public:
bool running=true;
while
and 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 th1
wait 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