QT学习

编程入门 行业动态 更新时间:2024-10-17 19:30:24

<a href=https://www.elefans.com/category/jswz/34/1769097.html style=QT学习"/>

QT学习

上位机用户的输入可能需要通过串口发送到下位机,而下位机返回的数据信息也需要显示在上位机上,因此主窗体线程和串口子线程之间是必须通信的。

正文

本文是继上一篇QT学习_14_一种开线程来实现串口通信方法-CSDN博客来继续专门探讨线程之间通信的问题,以及一些注意事项的。Qt真🐂🍺,这个彩虹屁我先吹为敬。 为什么夸Qt🐂🍺呢,因为他们线程间的通信真的超级方便!超级简单,当然也有可能是我以前见识少了。

废话不多说,我先把代码放上来吧

主窗口类叫fugu,我自己取的名字,含义不必深究哈,下面是fugu的构造函数

fugu::fugu(QWidget *parent) :QMainWindow(parent),ui(new Ui::fugu)
{ui->setupUi(this);// 串口通信单独开一个线程m_pserial_port = new ESerialPort;m_pthread_serial_port = new QThread(this);m_pserial_port->moveToThread(m_pthread_serial_port);m_pthread_serial_port->start();connect(this, &QObject::destroyed,[=](){m_pthread_serial_port->exit();m_pthread_serial_port->wait();delete m_pserial_port;});// 连接 主线程【连接】|【断开】按钮 → 串口处理线程connect(this, SIGNAL(sg_pushButton_connect_clicked(QString,QString)), m_pserial_port, SLOT(slot_on_pushButton_connect_clicked(QString,QString)));// 连接 主线程【刷新】按钮 → 串口处理线程connect(this, SIGNAL(sg_pushButton_Refresh_clicked()), m_pserial_port, SLOT(slot_on_pushButton_Refresh_clicked()));// 连接 主线程 向串口发送指令 → 串口处理线程connect(this, SIGNAL(sg_data_send(QByteArray,int)), m_pserial_port, SLOT(slot_data_send(QByteArray,int)));// 连接 主线程 同步参数 → 串口处理线程connect(this, SIGNAL(sg_para_synchronous(float,float,int16_t,float,float)), m_pserial_port, SLOT(slot_para_synchronous(float,float,int16_t,float,float)),Qt::BlockingQueuedConnection);// Qt::BlockingQueuedConnection// 阻塞连接:此连接方式只能用于信号发出的线程 和 槽函数的对象不再一个线程中才能用。发出信号后,当前线程会阻塞,等待槽函数执行完毕后才继续执行// 连接 串口处理线程 addlog → 主线程connect(m_pserial_port, SIGNAL(sg_addlog(QString, QColor, QColor)), this, SLOT(slot_addlog(QString, QColor, QColor)));// 连接 串口处理线程 刷新串口列表 → 主线程connect(m_pserial_port, SIGNAL(sg_refresh_serial_port_list()), this, SLOT(slot_refresh_serial_port_list()));// 连接 串口处理线程 设置【连接】【断开】按钮文本 → 主线程connect(m_pserial_port, SIGNAL(sg_pushButton_connect_setText(QString)), this, SLOT(slot_pushButton_connect_setText(QString)));// 连接 串口处理线程 设置【开始】【结束】按钮文本 → 主线程connect(m_pserial_port, SIGNAL(sg_pushButton_start_sweep_frequency_setText(QString)), this, SLOT(slot_pushButton_start_sweep_frequency_setText(QString)));// 连接 串口处理线程 初始化bode图 → 主线程connect(m_pserial_port, SIGNAL(sg_bode_init()), this, SLOT(slot_bode_init()));// 连接 串口处理线程 更新bode图 → 主线程connect(m_pserial_port, SIGNAL(sg_bode_update(float, float, float)), this, SLOT(slot_bode_update(float, float, float)));// 连接 串口处理线程 保存bode图 → 主线程connect(m_pserial_port, SIGNAL(sg_bode_save()), this, SLOT(slot_bode_save()));// 连接 串口处理线程 设置LED灯 → 主线程connect(m_pserial_port, SIGNAL(sg_set_led(int)), this, SLOT(slot_set_led(int)));
}

下面给出fugu.h 

class fugu : public QMainWindow
{Q_OBJECTpublic:explicit fugu(QWidget *parent = nullptr);~fugu();signals:void sg_pushButton_Refresh_clicked();void sg_pushButton_connect_clicked(QString,QString);void sg_data_send(QByteArray,int);void sg_para_synchronous(float,float,int16_t,float,float);
private slots:void slot_pushButton_connect_setText(QString);void slot_pushButton_start_sweep_frequency_setText(QString);void slot_refresh_serial_port_list();void slot_addlog(QString, QColor, QColor);void slot_bode_init();void slot_bode_update(float,float,float);void slot_bode_save();void slot_set_led(int);
private:Ui::fugu *ui;ESerialPort *m_pserial_port;QThread * m_pthread_serial_port;};

我先把自定义的 ESerialPort的代码也贴出来,然后一并讲吧

#ifndef ESERIALPORT_H
#define ESERIALPORT_H#include <QtCore/QObject>
#include <QSerialPort>
#include <QString>class ESerialPort : public QSerialPort
{Q_OBJECT
public:signals:void sg_addlog(QString, QColor, QColor);void sg_refresh_serial_port_list();void sg_pushButton_connect_setText(QString);void sg_pushButton_start_sweep_frequency_setText(QString);void sg_bode_init();void sg_bode_update(float, float, float);void sg_bode_save();void sg_set_led(int);public slots:void slot_on_pushButton_Refresh_clicked();void slot_on_pushButton_connect_clicked(QString,QString);void slot_data_receive();void slot_data_send(QByteArray,int);void slot_para_synchronous(float,float,int16_t,float,float);private:};
#endif // ESERIALPORT_H

QT线程间通信是用connect函数来实现的, 我开篇之所以说QT🐂🍺,是因为connect里面只要信号函数和槽函数的参数定义一致,就可以传递任意类型的变量,什么QString啊,QColor啊,QByteArray啊,这些都是可以直接传递的。更🐂🍺的是,一个对象发送的信号,可以在其他任何一个对象里面接收到这个信号,而具体接不接收这个信号,对这个信号做出响应,就要看是否用connect函数把发送的信号与槽函数连接起来了。

需要注意的一点是, connect一般都是放在主窗体类的构造函数里面的,因为自定义串口类里面是无法使用主窗体类的指针的。而自定义串口类的对象是定义在主窗体类中的。 

fugu.cpp里面我们调用了很多次connect函数, 主要可以分成两个部分:

  • 一部分是m_pserial_port给fugu发送信号,fugu接收信号,然后处理。
  • 一部分是fugu给m_pserial_port发送信号,m_pserial_port接收信号,然后处理

槽函数的作用是具体接到这个信号我怎么处理,这个是需要在.cpp里面有定义的。文中没有贴相关代码哈。而信号函数则是只用声明不用定义的。那么我们怎么自己发送这个信号呢? 举个例子你就一目了然。

emit sg_pushButton_connect_clicked(ui->pushButton_start_sweep_frequency->text(), ui->comboBox_serial_port->currentText());

emit就是发送信号的关键字,sg_pushButton_connect_clicked就是信号函数,ui->pushButton_start_sweep_frequency->text(), ui->comboBox_serial_port->currentText()则是三个发送给槽函数的参数。

关于信号与槽的相关知识这里就不多说了。 这里的重点我再说一遍,就是只要信号函数和槽函数的参数定义一致,就可以传递任意类型的变量

高级问题

下面谈一个高级点的问题,我项目上遇到一个真实的问题,就是点击一个按钮,我需要发送了好几个信号给子线程(直白点就是需要串口发好几帧数据包给下位机),但子线程执行不过来,只执行了其中的一部分信号。

那这个时候怎么办呢?

方法1、connect第5个参数(不推荐)

connect(this, SIGNAL(sg_para_synchronous(float,float,int16_t,float,float)), m_pserial_port, SLOT(slot_para_synchronous(float,float,int16_t,float,float)),Qt::BlockingQueuedConnection);

connect的第5个参数是, Qt::BlockingQueuedConnection
阻塞连接:此连接方式只能用于信号发出的线程 和 槽函数的对象不再一个线程中才能用。发出信号后,当前线程会阻塞,等待槽函数执行完毕后才继续执行

这种操作多了,主窗体类就卡死了。 如果阻塞的时候需要执行其他的信号的槽函数,直接凉凉了。 

方法2、用定时器timer,间隔一段时间分别发送(强推

QTimer * timer1 = new QTimer(this);
QTimer * timer2 = new QTimer(this);
QTimer * timer3 = new QTimer(this);// 启动定时器
timer1->start(1000);
connect(timer1,&QTimer::timeout,[=](){emit sg_data_send(m_sendbuf1,k1);timer1->stop();delete timer1;
});timer2->start(2000);
connect(timer2,&QTimer::timeout,[=](){emit sg_data_send(m_sendbuf2, k2);timer2->stop();delete timer2;
});timer3->start(3000);
connect(timer3,&QTimer::timeout,[=](){emit sg_data_send(m_sendbuf3, k3);timer3->stop();delete timer3;
});

用定时器的方式,既不会阻塞主线程,也能控制留给子线程响应我发送信号的时间。 也是我最终选择的方案。 

更多推荐

QT学习

本文发布于:2023-11-15 19:37:41,感谢您对本站的认可!
本文链接:https://www.elefans.com/category/jswz/34/1605160.html
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系,我们将在24小时内删除。
本文标签:QT

发布评论

评论列表 (有 0 条评论)
草根站长

>www.elefans.com

编程频道|电子爱好者 - 技术资讯及电子产品介绍!