本文主要是记录自己是如何仿写串口助手并实现效果的(本文并没有串口测试,但是其他按键功能已经编写成功)
前言
我也是在b站学习的QT,之前学习了C++的基础知识,那么在QT中就能够很好的运用出来了,并且本人之前有学习过安卓,对GUI开发比较熟练,所以如果觉得自己基础不好的可以先看看C++的知识。本文直接粘贴全部代码并逐步讲解。
一、显示效果
ui是自己实现的,可以去查找一些类似的串口助手编写,其中运动模式、下载模式,隐藏面板,隐藏历史都还未编写逻辑,主要功能已经实现。
二、讲解代码
都说万事开头难,我们要写一个串口助手,我们就需要先写一个串口助手的界面,我们在把里面的逻辑实现即可。
1.UI布局
我们先讲一下所需要的控件:双击ui文件打开(拖动左边的控件到中间的编辑框):
Label标签:用来标志控件,主要是用来告诉用户这个是用来做什么的,通常用来写文字。
Horizontal Spacer:横向弹簧,用来保持两个控件的控距,可以在右下角修改弹簧大小来实现控件距离的控制。
Vertical Spacer:纵向弹簧,效果和横向弹簧一样,只是作用对象时方向是上下
PushButton:按钮,用来点击来触发其他事件
CheckBox:勾选框,用来判断用户是否点击,作用和按钮差不多,但是这个可直接看到结果
GroupBox:框柱大的集合,主要也是用来调整距离
ComboBox:下拉框,可设置不同的值供选择
LineEdit:行编辑,提供给用户来编辑一行数据
TextEdit:文本便捷,效果差不多和行编辑一样
PlainTextEdit:追加编辑,通常用于接收数据显示
在拖动完控件后,我们需要修改不同的控件名字,用来在代码中查找到,修改名字只需要单击一下要修改的控件,在右上角会有显示,按需修改即可(一般使用驼峰命名)。
主要用到就这些控件,接下需要学会的是灵活布局:
横向布局就是让控件按行排列,纵向布局就是让控件纵向排列,栅格布局就是让控件一个接一个排列,像教室里的上课座位一样。
一般每几个控件就能实现横向布局或纵向布局,全部固定好后在实现栅格布局
2.信号和槽
我们通常使用的控件具有不同的信号,我们可以在帮助文档中查找到,如QPushButton:
**我们可以看到哪些信号会触发槽函数,QT中特有的信号和槽机制,可以让控件在接收到相对应的信号是触发对应的槽函数。**当然我们也可以自己编写槽函数,自定义编写槽函数需要满足一下几个条件。
自定义编写槽函数
1.在你的类中声明自定义槽函数。槽函数是普通的成员函数,但在声明时需要使用slots关键字进行修饰。例如
class MyCustomClass : public QObject
{
Q_OBJECT
public slots:
void myCustomSlot();
};
2.在类的实现文件(.cpp)中定义槽函数。你可以像编写普通成员函数一样来实现自定义的槽函数。例如:
void MyCustomClass::myCustomSlot()
{
// 这里编写槽函数的具体实现逻辑
// ...
}
3.将槽函数和信号连接起来。槽函数可以通过调用Qt的信号与槽机制来响应特定的信号。一般情况下,你可以在构造函数或其他适当的地方,使用connect函数来建立槽函数和信号的连接。例如:
MyCustomClass::MyCustomClass()
{
// 假设有一个QPushButton的点击信号连接到myCustomSlot()槽函数
QPushButton* button = new QPushButton("Click me");
connect(button, &QPushButton::clicked, this, &MyCustomClass::myCustomSlot);
}
connect
connect
函数是Qt中用于建立信号与槽连接的函数。它允许你将一个信号连接到一个槽函数,以便在信号发出时执行槽函数的代码。
在Qt中,信号是一种特殊的成员函数,用于通知其他对象某个事件的发生。当满足特定条件时,一个对象可以发出一个信号。槽函数是普通的成员函数,用于响应信号的发出并进行相应的处理。
connect
函数用于连接信号和槽函数,建立二者之间的关联。它的基本语法如下:
connect(sender, &SenderClass::signal, receiver, &ReceiverClass::slot);
其中,sender
是发出信号的对象的指针(或者是静态成员函数所属的类),signal
是发出的信号,receiver
是接收信号的对象的指针,slot
是接收信号时要执行的槽函数。
需要注意的是,信号和槽函数的参数类型必须匹配,或者是可以进行隐式转换的类型。此外,要确保信号和槽函数的声明都在QObject
的子类中,并在类的声明中使用Q_OBJECT
宏。
connect
函数可以连接不同对象之间的信号和槽函数,可以连接同一个对象的不同信号和槽函数,也可以连接不同信号和不同槽函数。一个信号可以连接多个槽函数,多个信号也可以连接到同一个槽函数。
通过使用connect
函数,你可以将对象间的通信通过信号和槽机制来实现。这种机制使得对象之间的耦合度降低,并提供了一种方便灵活的方式来处理事件。
自动实现槽函数
通常我们使用控件时,QT已经帮我们写好了槽函数,我们无需再自己编写connet,只需要在UI中右击控件,点击转到槽,然后确定自己选择的信号即可。这样我们就可以在槽函数中编写其中的逻辑了。
代码讲解:
QTSerial.pro
需要注意的是使用QT中的Serial函数需要在QT += core gui 加入serialport,这个可以在帮助文档中查看到
#-------------------------------------------------
#
# Project created by QtCreator 2023-07-16T13:41:42
#
#-------------------------------------------------
QT += core gui serialport
greaterThan(QT_MAJOR_VERSION, 4): QT += widgets
TARGET = QTSerial
TEMPLATE = app
# The following define makes your compiler emit warnings if you use
# any feature of Qt which has been marked as deprecated (the exact warnings
# depend on your compiler). Please consult the documentation of the
# deprecated API in order to know how to port your code away from it.
DEFINES += QT_DEPRECATED_WARNINGS
# You can also make your code fail to compile if you use deprecated APIs.
# In order to do so, uncomment the following line.
# You can also select to disable deprecated APIs only up to a certain version of Qt.
#DEFINES += QT_DISABLE_DEPRECATED_BEFORE=0x060000 # disables all the APIs deprecated before Qt 6.0.0
SOURCES += \
main.cpp \
qtserial.cpp
HEADERS += \
qtserial.h
FORMS += \
qtserial.ui
qtserial.h
#ifndef QTSERIAL_H
#define QTSERIAL_H
#include <QMainWindow>
#include <QSerialPort>
#include <QMessageBox>
#include <QComboBox>
#include <QCheckBox>
namespace Ui {
class QTSerial;
}
class QTSerial : public QMainWindow
{
Q_OBJECT
public:
explicit QTSerial(QWidget *parent = 0);
~QTSerial();
private slots://槽函数必须在这声明
void on_OpenSerialBt_clicked();//打开串口按钮的槽函数声明
void readyRead_slots();//准备读取的槽函数声明
void on_sendBt_clicked();//发送按钮的槽函数声明
void on_cleanSendEdit_clicked();//清空发送区的槽函数声明
void on_CleanRec_clicked();//清空接收区的槽函数声明
void on_HexPrint_stateChanged(int arg1);//进制转换的槽函数声明
private:
Ui::QTSerial *ui;
QSerialPort *serialport;//定义一个QSerialPort的指针变量,需要包含头文件<QSerialPort>,在QT中,包含类的头文件是无.h后缀的
};
#endif // QTSERIAL_H
qtserial.cpp
#include "qtserial.h"
#include "ui_qtserial.h"
#include <QDebug>
#include <QSerialPortInfo>
QTSerial::QTSerial(QWidget *parent) :
QMainWindow(parent),
ui(new Ui::QTSerial)
{
ui->setupUi(this);
serialport = new QSerialPort(this);//new一个对象出来
QStringList serialNamePort;//存储串口名称
connect(serialport, SIGNAL(readyRead()), this, SLOT(readyRead_slots()));//当有数据进来的时候会触发这个槽函数
foreach(const QSerialPortInfo &info, QSerialPortInfo::availablePorts())//自动搜索串口信息
{
serialNamePort << info.portName();//将搜索到的串口信息给定义的类
}
ui->SerialBox->addItems(serialNamePort);
}
QTSerial::~QTSerial()
{
delete serialport;
delete ui;
}
void QTSerial::on_OpenSerialBt_clicked()
{
if(serialport->open(QIODevice::ReadWrite) == true)
{
QMessageBox::information(this, "提示", "打开成功");
}
else
{
QMessageBox::information(this, "提示", "打开失败");
}
QString setBaudRate = ui->BoundBox->currentText();
QString setDateBits = ui->DataBitBox->currentText();
QString setParity = ui->ParityBox->currentText();
serialport->setPortName(ui->SerialBox->currentText());//设置端口号
switch (setBaudRate.toInt()) {
case 4800:
serialport->setBaudRate(4800);
break;
case 9600:
serialport->setBaudRate(9600);
case 115200:
serialport->setBaudRate(115200);
break;
default:
break;
}
switch (setDateBits.toInt()) {
case 7:
serialport->setDataBits(QSerialPort::Data7);
break;
case 8:
serialport->setBaudRate(QSerialPort::Data8);
default:
break;
}
if(ui->StopBitBox->currentText() == "1"){
serialport->setStopBits(QSerialPort::OneStop);
}else if(ui->StopBitBox->currentText() == "1.5"){
serialport->setStopBits(QSerialPort::OneAndHalfStop);
}else if(ui->StopBitBox->currentText() == "2"){
serialport->setStopBits(QSerialPort::TwoStop);
}
if(setParity == "None")
{
serialport->setParity(QSerialPort::NoParity);
}
}
void QTSerial::readyRead_slots()//接收数据
{
QString buf;
buf = QString(serialport->readAll());
ui->receTextEdit->appendPlainText(buf);
}
void QTSerial::on_sendBt_clicked()
{
serialport->write(ui->sendlineEdit->text().toUtf8().data());
}
void QTSerial::on_cleanSendEdit_clicked()
{
ui->sendlineEdit->clear();
}
void QTSerial::on_CleanRec_clicked()
{
ui->receTextEdit->clear();
}
void QTSerial::on_HexPrint_stateChanged(int arg1)
{
int sendLineEdit,decimalNumber1;
QString decimalNumber;
bool ok;
QString hexString;
switch (arg1) {
case 0:
decimalNumber = ui->sendlineEdit->text();
decimalNumber1 = decimalNumber.toInt(&ok, 16);
if (ok) {
ui->sendlineEdit->setText(QString::number(decimalNumber1));
} else {
QMessageBox::warning(nullptr, "错误", "转换失败!");
}
break;
case 2:
sendLineEdit = ui->sendlineEdit->text().toInt();
hexString = QString("%1").arg(sendLineEdit, 0, 16);
ui->sendlineEdit->setText(hexString);
break;
default:
break;
}
}
总结
这就是仿写串口助手了,基本逻辑功能已经实现了,如果有什么错误请纠正。