全球新资讯:QT多线程实战_Qt多线程开发项目

来源:QT教程 2023-06-01 19:37:36

需求的提出

窗口本身就是一个死循环,在这样一个死循环中执行任何耗时的操作,都会导致程序崩溃。所以多线程对于窗口编程而言是必要的。

例如,在窗口中拖入一个 pushButton 和 lineEdit ,将 pushButton 的名字改为 pbStart ,然后为其绑定一个函数,函数中创建一个死循环,并让死循环中的内容实时输出到 lineEdit 。


(资料图片)

接下来设计一个逻辑,当点击 pbStart 之后,开始执行死循环,同时按钮内容变为 Stop ;当按钮内容为 Stop 时,点击按钮,停止执行死循环。

所以,需要设计一个用于控制循环是否继续执行的成员变量,在 MainWindow 的头文件中添加私有成员 bool flag 。在 cpp 文件中添加 flag = true 。

然后转到设计界面 ,右键 pbStart 按钮->转到槽 ->clicked() 。从而 MainWindow 中添加了一个名为 on_pbStart_clicked 的函数,填充其内容为

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));    }}

复制

Jetbrains全家桶1年46,售后保障稳定

结果运行之后,果然陷入了死循环,程序也无法响应了,最过分的是 lineEdit 并没有变化,这个时候就要考虑多线程。

多线程

QThread 是Qt中最基础的线程类,每个实例都可以控制一个线程。其传统的调用方式是,新建一个继承 QThread 的类,然后将耗时任务写入 run 函数。而自QT4.4之后,则建议通过 moveToThread() 函数来调用多线程。

首先新建一个类,在项目中 Ctrl + N ,在弹出对话框中选择 Files and Classes ->C/C++ ->C++ Class ,定义类的名称为 ThTest ,并选中 QObject 。

令该类继承 QObject ,将头文件中的 ThTest 改为

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

复制

相应地, cpp 文件的内容为

#include \"thtest.h\"#include #include ThTest::ThTest(){    }ThTest::~ThTest(){    }void ThTest::Func(){        int NowNum = 0;    while(true){            NowNum++;        qDebug()<

复制

然后更改 mainwindow 的代码,在其头文件内容如下

#ifndef MAINWINDOW_H#define MAINWINDOW_H#include #include #include #include #include \"thtest.h\"QT_BEGIN_NAMESPACEnamespace Ui {  class MainWindow; }QT_END_NAMESPACEclass MainWindow : public QMainWindow{ Q_OBJECTpublic:MainWindow(QWidget *parent = nullptr);~MainWindow();signals:void ToThread(); // 信号private slots:void on_pbStart_clicked();private:Ui::MainWindow *ui;QThread *qThTest;ThTest *th1;};#endif

复制

然后将 cpp 文件中的 on_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();}

复制

其中, connect 将 ToThread 函数和 ThTest 中的 Func 函数绑定在了一起。也就是说,当这边发射 ToThread 的信号的时候, Th1 会执行 Func 这个函数。

所以,当线程启动后,通过 emit 发射 ToThread 信号,果然命令行中会持续输出数字了,同时窗口并不会死掉。

到了这一步,其实已经可以处理一些多线程任务了,但还不能把递增的 NowNum 显示到主窗口上,从而让 lineEdit 看上去有些鸡肋。为了实现在窗口上显示递增的数字,接下来需要做的就是线程间的通信。

线程间通信

得益于Qt的信号槽机制,多线程之间的通信并不复杂。乃至于,可以广义地认为 emit ToThread() 本身也是一个线程间通信的过程。

所以只需在 on_pbStart_clicked 中添加一条

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

复制

意思就是 th1 发射一个 sendInt(int) , this 接收一个 getInt(int) ,这两个函数的名字无所谓,但一定不包含形参,而只有形参的数据类型。

接下来,在 thtest.h 中添加 sendInt ,

signals:void sendInt(int);

复制

并更改其 Func 函数

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

复制

最后,在 mainwindow.h 中添加

private slots:void getInt(int);

复制

以及 cpp 文件中的

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

复制

这样,在点击 start 之后,就可以看到 lineEdit 上数字的变化了。

终止多线程

最后,回到一开始的需求,是点击 start 开始,然后按钮变为 stop ,点击 stop 后再停止。

考虑到 terminate 并不安全,故而采用终结 while 的方式来退出死循环。方法是在 ThTest 中添加一个 bool 类型的成员 running ,即在头文件中添加

public:bool running=true;

复制

并更改源文件中的 while 循环

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

复制

最后修改 on_pbStart_clicked

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

复制

并把 th1 等初始化过程移除去

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);}

复制

结果线程果然终止了

【领 QT开发教程 学习资料, 点击下方链接莬费领取↓↓ ,先码住不迷路~】

点击这里:

发布者:全栈程序员栈长

出处:https://javaforall.cn/234553.html原文链接:https://javaforall.cn

关键词:

相关新闻