使用,学习QT的背景
刚入职新公司,工作是嵌入式软件,工作内容包括使用QT进行一些软件的开发等,以前没有接触过QT,特意创建第一篇博客,用作QT的学习过程记录
入职后,公司前辈要求使用QT写一个软件,接收硬件设备传回的数据并显示,同时软件可以对设备的工作方式进行设定,使用TCP通信协议。
C++和TCP通讯还算比较熟悉,所以前期代码没有问题,Debug得到的数据已经达到预期,但是,在试图把信息显示在UI界面中的label控件中的时候,问题出现了:
由于软件在运行过程中需要不断的向设备发出数据,取回数据,需要持续占用资源。所以用到了多线程进行处理,然而,在QT中,只有主线程可以对UI进行操作。所以,子线程不能操作UI界面。正因此才接触到了QT的信号与槽机制
对信号和槽函数的理解:
信号和槽函数就像一根插排,有插头(信号),有插座(槽函数),它们之间用电线连起来(connect函数),所以当插头插上电之后,插座也会有对应的响应,比如指示灯亮起。。。
QT中的信号和槽可以跨线程传递,也就是说,一旦信号和槽绑定完成后,只要有信号发出,那么对应的槽函数就会被执行,无论两者是不是在同一个线程中。
代码表示:
首先是信号(相当于插头)
mywrite.h文件 新建的文件,用作数据的处理
/*这个是mywrite.cpp文件,用作数据处理*/
#ifndef MYWRITE_H
#define MYWRITE_H
#include <QObject>
class Mywrite : public QObject
{
Q_OBJECT
public:
explicit Mywrite(QObject *parent = 0);
void run(); //假设这个是数据处理线程(不要在意继承什么的细节,多线程之后再发)
//它在运行过程中,需要显示数据的时候,就发射下边的信号 ↓
signals: //这个是信号集,代表了信号的集合,这一栏下边的所有函数都是信号
//信号只需要在头文件中声明即可,不需要实现
void send_output_text(QString); //这个是信号(插头),可以看到,为了满足我们的需求
//它是有参数的(当然,多参数或者无参数都可以)
//这个信号的参数是 QString 类型的
public slots:
};
#endif // MYWRITE_H
mywrite.cpp文件,这个文件用作数据处理
/*mywrite.cpp 文件,这个文件用作数据处理 */
#include "mywrite.h"
Mywrite::Mywrite(QObject *parent) : QObject(parent)
{
}
void Mywrite::run() //假定的数据处理函数
{
QString data;
/*
*
对数据进行发送,接受,处理操作,假设最终获取到了有用数据,并保存在变量 data 中
*/
//如果需要把data显示在UI界面上,就可以调用设定好的信号
emit send_output_text(data); //emit 发射的意思,执行这个操作之后,就会发出一个信号
}
widget.h 头文件,创建工程自带的, 代码中加了很多注释,就不多打字了
// 这个是widget.h 文件
#ifndef WIDGET_H
#define WIDGET_H
#include <QWidget>
namespace Ui {
class Widget;
}
class Widget : public QWidget
{
Q_OBJECT
public:
explicit Widget(QWidget *parent = 0);
~Widget();
private slots: //这个代表槽函数集合
void set_outputt_text(QString); //这个是创建的一个文本显示槽函数
//用来接受子线程传过来的文本并显示出来
//我的UI界面中,用了一个label控件显示数据
//label控件名字叫做 label_output
private:
Ui::Widget *ui;
};
#endif // WIDGET_H
widget.cpp 文件,也是创建工程自带的,这个文件中包含了对槽函数的定义,信号与槽函数的连接
/*widget.cpp 创建工程自带的文本,这个CPP里边主要包含了UI界面的一些操作,比如点击按钮
输入文本等*/
#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget *parent) :
QWidget(parent),
ui(new Ui::Widget) /*构造函数*/
{
ui->setupUi(this);
Mywrite myw; //实例化一个Mywrite的对象出来
//这个地方对信号和槽函数进行绑定,绑定使用的函数是: connect
//connect函数在QObject空间内,也可以省略前边的QObject,直接写connect
//connect的4个参数是:
//connect(信号的发出者是谁, 发的哪个信号, 信号的接受者是谁, 接收到信号做什么操作);
//有了上边的基础, 我们就知道了对应的4项是谁:
//信号的发出者: 数据处理函数发出的信号,也就是Mywrite类实例化出的 myw
//发出的信号: Mywrite类中的信号:void send_output_text(QString)
//信号的接受者: UI界面, 本函数是widget的构造函数,所以可以使用this指针,代表自己
//接到信号后的操作: 把接到的QString类型字符串显示到label上,对应槽函数: void set_output_text(QString)
//下边这行代码就完成了插头(信号)和插座(槽函数)的绑定
QObject::connect(&myw, SIGNAL(send_output_text(QString)), this, SLOT(set_outputt_text(QString)));
}
Widget::~Widget() /*析构函数*/
{
delete ui;
}
void Widget::set_output_text(QString qstr) //这里就是槽函数的函数实现
{
ui->label_output->setText(qstr); //对label进行文本设置,显示内容为参数内容
}
注意:
这套代码是不能运行的,因为实际项目要用到多线程,然后启动线程后才能进行数据处理,然后发送信号。这套代码是周末写的,用作学习记录,也希望能帮到刚接触QT的朋友。