本篇文章为记录下班之后空闲时间,断断续续,参照野火串口助手界面,个人编写的串口助手程序示例。
一、分析程序需要的功能
- 串口助手程序,必然需要QSerialPort类,因此需要写个自定义类,来处理对QSerialPort的各种操作。
- 点击可用串口下拉框应实时更新当前可用串口,因此需要写个自定义类,继承自QCombobox,获取鼠标左键点击事件,在点击事件中更新可用串口。
- 我想将UI界面和串口类分离开,因此需要一个自定义线程托管类,通过MoveToThread()将窗口类移到子线程中去,通过信号槽来实现子线程和主线程间的各种通信。
- 本示例界面参照的是野火调试助手的串口功能界面,野火调试助手下载链接为:野火调试助手,在实际使用野火调试助手过程中,发现在多项发送功能中,需要实现动态添加界面控件,因此需要写一个自定义类,继承自QTabWidget,通过代码实现动态添加界面控件。
二、具体实现
1 自定义QSerialPort处理类
class MySerialPort : public QObject
{
Q_OBJECT
public:
MySerialPort();
~MySerialPort();
private:
/**
*@name get_useable_serial_portname
*@brief get cur can be used serial portname
*@param
*@return QList<QSerialPortInfo>
*@note
*@author Mydolen
*@date 2022-12-09
*/
QList<QSerialPortInfo> get_useable_serial_portname();
/**
*@name open_port
*@brief open serial port
*@param QString portname,
quint32 baudrate = QSerialPort::Baud115200,
QSerialPort::DataBits DataBits = QSerialPort::Data8,
QSerialPort::Parity Parity = QSerialPort::NoParity,
QSerialPort::StopBits StopBits = QSerialPort::OneStop,
QSerialPort::FlowControl FlowControl = QSerialPort::NoFlowControl
*@return void
*@note
*@author Mydolen
*@date 2022-12-09
*/
void open_port(QString portname,
quint32 baudrate = QSerialPort::Baud115200,
QSerialPort::DataBits DataBits = QSerialPort::Data8,
QSerialPort::Parity Parity = QSerialPort::NoParity,
QSerialPort::StopBits StopBits = QSerialPort::OneStop,
QSerialPort::FlowControl FlowControl = QSerialPort::NoFlowControl);
/**
*@name close_port
*@brief close port
*@param
*@return void
*@note
*@author Mydolen
*@date 2022-12-12
*/
void close_port();
/**
*@name read_receive_data
*@brief slot of readyread signal
*@param
*@return QSharedPointer<QByteArray>
*@note
*@author Mydolen
*@date 2022-12-11
*/
QSharedPointer<QByteArray> read_receive_data();
/**
*@name write_to_serial
*@brief write to serial
*@param QSharedPointer<QByteArray> data
*@return void
*@note
*@author Mydolen
*@date 2022-12-13
*/
void write_to_serial(QSharedPointer<QByteArray> data);
private:
QSerialPort *m_serial;
QString cur_portname;
signals:
void sig_get_serial_portname_list(); //外部获取当前可用串口列表信号
void sig_open_port(QString portname,
quint32 baudrate = QSerialPort::Baud115200,
QSerialPort::DataBits DataBits = QSerialPort::Data8,
QSerialPort::Parity Parity = QSerialPort::NoParity,
QSerialPort::StopBits StopBits = QSerialPort::OneStop,
QSerialPort::FlowControl FlowControl = QSerialPort::NoFlowControl); //外部打开串口信号
void sig_close_port(); //外部关闭串口信号
void sig_write_data(QSharedPointer<QByteArray> data); //外部向串口写数据信号
void sig_emit_serial_portname_list(QSharedPointer<QList<QSerialPortInfo>> list_pointer);//返回当前可用串口列表
void sig_emit_read_data(QSharedPointer<QByteArray> data); //向外部发送读取到的数据
void sig_error_occured(QString error_str); //向外部发送错误信息
void sig_normal_info(QString info); //向外部发送正常信息
};
2 自定义QComboBox控件
class MyComboBox : public QComboBox
{
Q_OBJECT
public:
MyComboBox(QWidget *parent = nullptr);
~MyComboBox();
protected:
virtual void mousePressEvent(QMouseEvent *e);
signals:
void left_button_clicked();
};
3 自定义线程托管类
class MyHostThread : public QThread
{
Q_OBJECT
public:
MyHostThread(QObject *be_hosted);
~MyHostThread();
};
4 自定义QTabWidget控件
class MyTabWidget : public QTabWidget
{
Q_OBJECT
public:
MyTabWidget(QWidget *parent = nullptr);
private:
/**
*@name init_thread
*@brief init thread
*@param
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void init_thread();
/**
*@name create_new_input_item
*@brief create new input item
*@param const int index
*@return QGridLayout*
*@note note
*@author Mydolen
*@date 2022-12-15
*/
QHBoxLayout* create_new_input_item(const int index);
/**
*@name create_new_tab_widget_item
*@brief create new tab
*@param const int index
*@return QGridLayout*
*@note note
*@author Mydolen
*@date 2022-12-15
*/
QGridLayout* create_new_tab_widget_item(const int index);
/**
*@name slot_add_new_tab
*@brief add new tab to tabwidget
*@param const int index
*@return void
*@note none
*@author Mydolen
*@date 2022-12-15
*/
void slot_add_new_tab();
/**
*@name slot_delete_one_tab
*@brief delete one tab
*@param
*@return void
*@note none
*@author Mydolen
*@date 2022-12-15
*/
void slot_delete_one_tab();
/**
*@name slot_turn_next_tab
*@brief turn next or pre tab
*@param bool next_or_pre
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void slot_turn_next_tab(bool next_or_pre);
/**
*@name slot_move_to_home_page
*@brief move to home or back page
*@param bool home_or_back
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void slot_move_to_home_page(bool home_or_back);
/**
*@name slot_jump_to_index
*@brief jump to index
*@param const int index
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void slot_jump_to_index(const int index);
/**
*@name slot_clear_cur_tab
*@brief clear cur tab
*@param
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void slot_clear_cur_tab();
/**
*@name slot_receive_button_group_signals_button
*@brief receive button group signals
*@param QAbstractButton *but
*@return void
*@note note
*@author Mydolen
*@date 2022-12-15
*/
void slot_receive_button_group_signals_button(QAbstractButton *button);
private:
int m_index;
QButtonGroup *m_but_group;
signals:
void sig_add_new_tab(); //增加一页控件
void sig_turn_next_tab(bool next_or_pre); //前、后一页
void sig_move_to_home_page(bool home_or_back); //首页、尾页
void sig_delete_one_tab(); //删除一页
void sig_clear_cur_tab(); //清空当前页
void sig_jump_to_index(const int index); //跳转到某页
void sig_cur_tab_index(const int index); //向外部发送当前页序号
void sig_max_tab_index(const int index); //向外部发送最大页序号
void sig_button_clicked(const QString str); //按钮按下发送对应LineEdit内的输入内容
};
三、界面展示
三、简要总结
- 本示例所应用的技术:
- 串口通讯
- 多线程
- 信号槽
- 智能指针
- HEX转码
- 自定义控件
- 动态变更界面控件
- 将来需要实现的功能:
- 自动发送功能。
- 保存到文件功能。
都不难,只是在写这篇文章的时候还没加上
- 本项目编译环境:Qt 6.2.4 Community \ MSVC 2019
- 本项目Gitee地址:MyProjectA