
Qt提供对线程的支持. 它提供了一些与平台无关的线程类. 要执行多线程方法,有两种方法.
Qt提供了QThread类. QThread类中有一个虚函数QThread :: run().

要创建一个新线程,我们只需要定义一个MyThread类,让它继承QThread,然后重新实现QThread :: run().
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QThread>
class MyThread : public QThread
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
~MyThread();
protected:
//QThread的虚函数
//线程处理函数
//不能直接调用,通过start()间接调用
void run();
signals:
void isDone(); //处理完成信号
signals:
public slots:
};
#endif // MYTHREAD_H
};
然后您可以编写要在运行中执行的操作,例如,可以等待5秒钟. 如果不是多线程qt多线程绘图qt多线程绘图,则在运行时单击窗口,窗口将显示为无响应.
那么您如何告诉线程结束?这可以使用qt的信号和时隙机制. 操作完成后,我们可以发出完成信号. 完成信号在声明文件中定义.
void MyThread::run()
{
//很复杂的数据处理
//需要耗时5秒
sleep(5);
emit isDone(); //发送完成信号
}
通过这种方式,我们已经完成了线程操作的编写.
现在,让我们首先布置一个简单的ui,仅使用一个LcdNumber和一个PushButton.


在当前窗口小部件头文件中定义一些必需的操作. 并加入我们定义的线程文件.
#ifndef MYWIDGET_H
#define MYWIDGET_H
#include <QWidget>
#include <QTimer>
#include "mythread.h" //线程头文件
namespace Ui {
class MyWidget;
}
class MyWidget : public QWidget
{
Q_OBJECT
public:
explicit MyWidget(QWidget *parent = 0);
~MyWidget();
void dealTimeout(); //定时器槽函数
void dealDone(); //线程槽函数
void stopThread(); //停止线程
private slots:
void on_pushButton_clicked();
private:
Ui::MyWidget *ui;
QTimer *myTimer; //声明变量
MyThread *thread; //线程对象
};
#endif // MYWIDGET_H
我们使用计时器让Lcd控件根据指定的时间更新数字. 当我们单击开始按钮时,计时器启动,并自动触发超时信号. 要捕获超时信号,请在DealTimerout()函数中写入所需的操作. 捕获超时后,将自动使用dealTimerout插槽功能.
dealTimerout()我们可以这样写:
void MyWidget::dealTimeout()
{
static int i = 0;
i++;
//设置lcd的值
ui->lcdNumber->display(i);
}
在小部件构造函数中,首先创建一个计时器并为线程函数分配空间:
myTimer = new QTimer(this);
thread = new QThread(thread); //分配空间
然后我们将信号和插槽关联起来:
//只要定时器启动,自动触发timeout
connect(myTimer, &QTimer::timeout, this, &MyWidget::dealTimeout);
![]()
在开始按钮的插槽功能中,启动计时器并启动线程. 需要注意的是,我们不能直接调用run函数,而可以通过start()间接调用线程函数.
void MyWidget::on_pushButton_clicked()
{
//若定时器没有工作
if(myTimer->isActive() == false)
{
myTimer->start(100);
}
//启动线程,处理数据
thread->start();
}
程结束时,我们收到了isDone信号,在此我们关闭了计时器:
void MyWidget::dealDone()
{
qDebug() << "it is over"; //打印线程结束信息
myTimer->stop(); //关闭定时器
}
我们选择退出窗口时关闭线程. 退出窗口时将触发被破坏的信号. 线程关闭的插槽功能实现如下:
void MyWidget::stopThread()
{
//停止线程
thread->quit();
//等待线程处理完手头工作
thread->wait();
}
最后,在小部件主窗口的构造函数中添加线程的关联信号和插槽:
connect(thread, &MyThread::isDone, this, &MyWidget::dealDone);
//当按窗口右上角x时,触发destroyed信号
connect(this, &MyWidget::destroyed, this, &MyWidget::stopThread);
现在,当我们启动程序时,窗口如下:


当我们单击“开始”按钮时,将触发计时器,启动线程,并且Lcd中的值每100ms更新一次:

5秒后,线程停止,发出isDone信号,执行DealDone插槽功能,显示其结束并关闭计时器:

再次单击,再次启动计时器,继续累积数字并将其设置为Lcd,单击x,程序退出并停止线程.
创建一个新项目,ui如图所示:

创建一个继承自QObject的新类,然后在该类中设置一个线程函数.
#ifndef MYTHREAD_H
#define MYTHREAD_H
#include <QObject>
class MyThread : public QObject
{
Q_OBJECT
public:
explicit MyThread(QObject *parent = 0);
~MyThread();
//线程处理函数
void MyTimeout();
void setFlag(bool flag = true);
signals:
void mySignal();
public slots:
private:
bool isStop;
};
#endif // MYTHREAD_H
通过bool变量控制线程的末尾,并通过发出mySignal()信号来调用处理插槽函数.

在小部件中定义如下:
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
#include "mythread.h"
#include <QThread>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
void dealSignal();
void dealClose();
signals:
void startThread(); //启动子线程的信号
private slots:
void on_pushButtonStart_clicked();
void on_pushButtonStop_clicked();
private:
Ui::Widget *ui;
MyThread *myT;
QThread *thread;
};
#endif // WIDGET_H
两个插槽函数dealSignal()和dealClose()分别与mySignal()和destroy()信号关联.
信号startThread()用于启动子线程.
在小部件的实现中,
各种功能的实现如下:
void Widget::dealSignal()
{
static int i = 0;
i++;
ui->lcdNumber->display(i);
}
//Start按钮
void Widget::on_pushButtonStart_clicked()
{
if(thread->isRunning() == true)
{
return;
}
//启动线程,但是没有启动线程处理函数
thread->start();
myT->setFlag(false);
//不能直接调用线程处理函数,直接调用导致线程处理函数和主线程在同一个线程
//myT->MyTimeout();
//只能通过 signal - slot方式
emit startThread();
}
//Stop按钮
void Widget::on_pushButtonStop_clicked()
{
if(thread->isRunning() == false)
{
return;
}
myT->setFlag(true);
thread->quit();
thread->wait();
}
void Widget::dealClose()
{
on_pushButtonStop_clicked();
delete myT;
}
在DealSignal中,增加Lcd号.
按下“开始”按钮时,将启动线程,将线程标志设置为flase,并通过发出startThread()信号来调用真实的线程函数MyThread :: MyTimeout.
按下“停止”按钮时,将线程标志设置为true并关闭线程.
由于未为myT指定父对象,因此我们需要手动释放内存. 单击x时,线程将关闭并删除.
运行如下所示:
本文来自电脑杂谈,转载请注明本文网址:
https://www.pc-fly.com/a/jisuanjixue/article-263237-1.html
领空
打缓
让有智慧