1 QT工程
1.1qt基础
qt的移植性非常的强。一套代码我们不用改太多,直接通用所有的平台。
不久的将来,qt会被用到MCU上,学习QT还是非常有意义的。
1.2做一个简单的qt界面
如何创建一个QT工程?
- 步骤一:

- 步骤二:
不要有中文路径
- 步骤三:

工程文件分析:
点击forms,然后双击ui文件,就可以进入ui编辑器。
ui编辑器面板介绍:
做一个简单的QQ登录界面,我们用到组件
放图片,放文本,放gif图的组件就是 qlabel
放账号和密码的对话框我们用的组件是 qlinedit
按钮我们使用的组件是 qpushbutton
1.3关联信号和槽
自动关联:在ui界面里,右键点击对应的控件->转到槽
自动关联会给我们的工程添加以下内容:
槽函数只能声明到private slots或者public slots 下面。(QT特有)
手动关联:使用connect这个函数。
connect(ui->logoBt,SIGNAL(clicked()),this,SLOT(logoBt_clicked_slots()));
connect(A,SIGNAL(B),C,SLOT(D));//当对象A发出B信号时候,就会触发对象C的槽函数D1.4添加图片
图标下载网址: iconfont-阿里巴巴矢量图标库
1、添加图片:
右键项目名->添加新文件->Qt->Qt Resource File
Resourrces文件夹下右键.qrc文件->Open with->资源编辑器-添加前缀(一般默认根文件)->Crtl+S 保存文件->添加文件 注意:记得保存!!!
2、引用图片
右击想要的控件->改变样式表->添加资源->border-image。可以添加多张照片。
1.5添加新的页面
右键项目名->添加新文件->Qt->Qt 设计师类界面->设置类名
26、28行,创建类的对象。问题:在这个类下随意创建一个对象就是我们在编辑的ui界面
void MainWindow::on_loginBt_clicked()
{
qDebug() << "loginBt_clicked";
QString ssid = ui->ssidEdit->text();
QString pwd = ui->pswdEdit->text();
if(ssid == "yyx" && pwd == "123")//判断密码
{
ctrl* ct = new ctrl;
ct->setGeometry(this->geometry());//读取窗口的高宽数据进行设置
ct->show();//显示跳转的页面
}
}
void ctrl::on_backBt_clicked()
{
this->close();//这句话就可以关闭本文件对应的界面
}2 QT三驾马车
qt下的串口编程,网络编程(TCP UDP),操作GPIO
3 串口编程
3.1自制串口调试助手
3.1.1串口调试助手界面设计
做一个串口调试助手需要用到的组件如下
接受框:
属性选择:
发送框:
UI设计界面如下:
3.1.2串口调试助手程序设计
- 由于版本比较高,会出现字体大小不合适的情况,需要在吗main.cpp里添加一段代码
#include "widget.h"
#include <QApplication>
#include <iconv.h>
int main(int argc, char* argv[])
{
if(QT_VERSION >= QT_VERSION_CHECK(5, 6, 0))//判断QT版本
{
QCoreApplication::setAttribute(Qt::AA_EnableHighDpiScaling);
}
QApplication a(argc, argv);
Widget w;
w.setWindowTitle("阿轩串口调试助手 V1.0.0");//界面程序名称
w.show();
return a.exec();
}- 需要在xxx.pro文件里上serialport库,QT += core gui serialport

界面操作代码
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QSerialPort> #include <QString> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget* parent = nullptr); ~Widget(); QSerialPort* serialPort = new QSerialPort(this); void serial_open_Bt_state();//串口打开时按钮盒选项的状态 void serial_close_Bt_state();//串口关闭时按钮盒选项的状态 private slots: void on_openBt_clicked(); void serialPortReadyRead_Slot(); void on_sendBt_clicked(); void on_clearBt_clicked(); void on_pushButton_1_clicked(); void on_pushButton_2_clicked(); void on_pushButton_3_clicked(); void on_pushButton_4_clicked(); void on_pushButton_5_clicked(); void on_pushButton_6_clicked(); void on_pushButton_7_clicked(); void on_pushButton_8_clicked(); void on_pushButton_9_clicked(); void on_pushButton_10_clicked(); void on_pushButton_11_clicked(); void on_pushButton_12_clicked(); void on_pushButton_13_clicked(); void on_pushButton_14_clicked(); void on_pushButton_15_clicked(); private: Ui::Widget* ui; }; #endif // WIDGET_H
#include "widget.h"
#include "ui_widget.h"
#include <QSerialPortInfo>
#include <QMessageBox>
bool serial_state = false;
Widget::Widget(QWidget* parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
QStringList serialNamePort;
foreach (const QSerialPortInfo& info, QSerialPortInfo::availablePorts())//自动检测端口
{
serialNamePort << info.portName();
}
ui->serialCb->addItems(serialNamePort);//自动检测到的端口输出给串口选择框
connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot()));//检测串口收到的数据
serial_close_Bt_state();//启动时默认是未打开
}
Widget::~Widget()
{
delete ui;
}
//串口打开之后一些按钮状态需要改变
void Widget::serial_open_Bt_state()
{
ui->sendBt->setEnabled(true);
ui->pushButton_1->setEnabled(true);
ui->pushButton_2->setEnabled(true);
ui->pushButton_3->setEnabled(true);
ui->pushButton_4->setEnabled(true);
ui->pushButton_5->setEnabled(true);
ui->pushButton_6->setEnabled(true);
ui->pushButton_7->setEnabled(true);
ui->pushButton_8->setEnabled(true);
ui->pushButton_9->setEnabled(true);
ui->pushButton_10->setEnabled(true);
ui->pushButton_11->setEnabled(true);
ui->pushButton_12->setEnabled(true);
ui->pushButton_13->setEnabled(true);
ui->pushButton_14->setEnabled(true);
ui->pushButton_15->setEnabled(true);
ui->serialCb->setEnabled(false);
ui->baundrateCb->setEnabled(false);
ui->dataCb->setEnabled(false);
ui->checkCb->setEnabled(false);
ui->stopCb->setEnabled(false);
}
//串口关闭后一些按钮状态也需要改变
void Widget::serial_close_Bt_state()
{
ui->sendBt->setEnabled(false);
ui->pushButton_1->setEnabled(false);
ui->pushButton_2->setEnabled(false);
ui->pushButton_3->setEnabled(false);
ui->pushButton_4->setEnabled(false);
ui->pushButton_5->setEnabled(false);
ui->pushButton_6->setEnabled(false);
ui->pushButton_7->setEnabled(false);
ui->pushButton_8->setEnabled(false);
ui->pushButton_9->setEnabled(false);
ui->pushButton_10->setEnabled(false);
ui->pushButton_11->setEnabled(false);
ui->pushButton_12->setEnabled(false);
ui->pushButton_13->setEnabled(false);
ui->pushButton_14->setEnabled(false);
ui->pushButton_15->setEnabled(false);
ui->serialCb->setEnabled(true);
ui->baundrateCb->setEnabled(true);
ui->dataCb->setEnabled(true);
ui->checkCb->setEnabled(true);
ui->stopCb->setEnabled(true);
}
//读取串口发来的信息并显示
void Widget::serialPortReadyRead_Slot()
{
QString buf;
buf = QString(serialPort->readAll());
ui->recvEdit->appendPlainText(buf);
}
//串口开关按钮
void Widget::on_openBt_clicked()
{
if(serial_state == false)
{
QSerialPort::BaudRate baudRate;//波特率
QSerialPort::DataBits dataBits;//数据位
QSerialPort::StopBits stopBits;//停止位
QSerialPort::Parity checkBits;//校验位
//读取选择的波特率
if(ui->baundrateCb->currentText() == "1200")
{
baudRate = QSerialPort::Baud1200;
}
else if(ui->baundrateCb->currentText() == "2400")
{
baudRate = QSerialPort::Baud2400;
}
else if(ui->baundrateCb->currentText() == "4800")
{
baudRate = QSerialPort::Baud4800;
}
else if(ui->baundrateCb->currentText() == "9600")
{
baudRate = QSerialPort::Baud9600;
}
else if(ui->baundrateCb->currentText() == "19200")
{
baudRate = QSerialPort::Baud19200;
}
else if(ui->baundrateCb->currentText() == "38400")
{
baudRate = QSerialPort::Baud38400;
}
else if(ui->baundrateCb->currentText() == "57600")
{
baudRate = QSerialPort::Baud57600;
}
else if(ui->baundrateCb->currentText() == "115200")
{
baudRate = QSerialPort::Baud115200;
}
//读取选择的数据位
if(ui->dataCb->currentText() == "5")
{
dataBits = QSerialPort::Data5;
}
else if(ui->dataCb->currentText() == "6")
{
dataBits = QSerialPort::Data6;
}
else if(ui->dataCb->currentText() == "7")
{
dataBits = QSerialPort::Data7;
}
else if(ui->dataCb->currentText() == "8")
{
dataBits = QSerialPort::Data8;
}
//读取选择的停止位
if(ui->stopCb->currentText() == "1")
{
stopBits = QSerialPort::OneStop;
}
else if(ui->stopCb->currentText() == "1.5")
{
stopBits = QSerialPort::OneAndHalfStop;
}
else if(ui->stopCb->currentText() == "2")
{
stopBits = QSerialPort::TwoStop;
}
//读取选择的效验位
if(ui->checkCb->currentText() == "none")
{
checkBits = QSerialPort::NoParity;
}
serialPort->setPortName(ui->serialCb->currentText());//设置串口号
serialPort->setBaudRate(baudRate);//设置波特率
serialPort->setDataBits(dataBits);//设置数据位
serialPort->setStopBits(stopBits);//设置停止位
serialPort->setParity(checkBits);//设置校验位
//打开并判断是否打开成功
if(serialPort->open(QIODevice::ReadWrite) == true)
{
//QMessageBox::information(this, "提示", "成功");
// ui->labelstate->setText("串口已打开");//弹窗
serial_state = true;
serial_open_Bt_state();
ui->openBt->setText("关闭串口");
}
else
{
QMessageBox::information(this, "提示", "失败");
}
}
else
{
serialPort->close();
// ui->labelstate->setText("串口关闭");//弹窗
serial_state = false;
serial_close_Bt_state();
ui->openBt->setText("打开串口");
}
}
void Widget::on_sendBt_clicked()
{
serialPort->write(ui->sendEdit->text().toLocal8Bit().data());//转为QByteString类型字符串,并且再转换成char*发送,防止乱码
serialPort->write("\r\n");
}
void Widget::on_clearBt_clicked()
{
ui->recvEdit->clear();
}
void Widget::on_pushButton_1_clicked()
{
serialPort->write(ui->lineEdit_1->text().toLocal8Bit().data());
}
void Widget::on_pushButton_2_clicked()
{
serialPort->write(ui->lineEdit_2->text().toLocal8Bit().data());
}
void Widget::on_pushButton_3_clicked()
{
serialPort->write(ui->lineEdit_3->text().toLocal8Bit().data());
}
void Widget::on_pushButton_4_clicked()
{
serialPort->write(ui->lineEdit_4->text().toLocal8Bit().data());
}
void Widget::on_pushButton_5_clicked()
{
serialPort->write(ui->lineEdit_5->text().toLocal8Bit().data());
}
void Widget::on_pushButton_6_clicked()
{
serialPort->write(ui->lineEdit_6->text().toLocal8Bit().data());
}
void Widget::on_pushButton_7_clicked()
{
serialPort->write(ui->lineEdit_7->text().toLocal8Bit().data());
}
void Widget::on_pushButton_8_clicked()
{
serialPort->write(ui->lineEdit_8->text().toLocal8Bit().data());
}
void Widget::on_pushButton_9_clicked()
{
serialPort->write(ui->lineEdit_9->text().toLocal8Bit().data());
}
void Widget::on_pushButton_10_clicked()
{
serialPort->write(ui->lineEdit_10->text().toLocal8Bit().data());
}
void Widget::on_pushButton_11_clicked()
{
serialPort->write(ui->lineEdit_11->text().toLocal8Bit().data());
}
void Widget::on_pushButton_12_clicked()
{
serialPort->write(ui->lineEdit_12->text().toLocal8Bit().data());
}
void Widget::on_pushButton_13_clicked()
{
serialPort->write(ui->lineEdit_13->text().toLocal8Bit().data());
}
void Widget::on_pushButton_14_clicked()
{
serialPort->write(ui->lineEdit_14->text().toLocal8Bit().data());
}
void Widget::on_pushButton_15_clicked()
{
serialPort->write(ui->lineEdit_15->text().toLocal8Bit().data());
}
4 软件打包成windows可执行文件
QT如何打包生成独立可执行.exe文件_qt打包成可执行程序-CSDN博客
4.1我们把工厂切换到release模式,然后编译
release模式:基本没有调试信息。
debug模式:有很多调试信息。
4.2改一下图标
先把图标加到工程所在文件夹。然后在pro文件里面添加RC_ICONS=serial_iocn.ico
注意:图标的格式必须为.ico这个格式的,其他格式不行。
4.3封包操作
4.3.1将QT程序使用Release编译**

4.3.2新建一个文件夹,将Release编译生成的exe文件复制到新建文件夹中
先找到Release编译生成的exe文件夹位置,与项目创建的文件夹有关: 
临时文件夹 --》 release --》 xx .exe文件
比如我的这个就是在D:\QtPro\build-Serial-Desktop_Qt_5_12_9_MinGW_64_bit-Release\release
把exe文件拷贝出来 
随便在哪创建一个空的文件夹,然后将.exe文件拷贝进去
比如我在E盘新建了QTtest文件夹 
4.3.3使用命令终端添加程序所需的依赖库
在开始菜单中找到Qt命令终端(版本可能不一样打开对应版本就行),进入刚才新建的文件夹目录,使用 windeployqt 对生成的exe 文件进行打配置动态库文件: 
一般来说,打开命令行终端后默认是在QT的安装路径下,这样需要先把路径切过去到exe文件的路径下再使用 windeployqt 命令 + .exe文件名操作
或者直接windeployqt + .exe文件绝对路径 
这样就成功了,可以双击exe文件测试是否可以正常打开。 
到这一步其实可以选择把整个文件夹打个压缩包,然后就可以发送到其他PC端使用了,只需解压缩即可。
如果还觉得麻烦,想只用一个exe文件就能独立工作,那就接着往下操作。
4.4合并
打包程序(下面的步骤只适用于Windows系统下)
4.4.1安装Enigma virtual box工具
Enigma Virtual Box是软件虚拟化工具,它可以将多个文件封装到应用程序主文件,从而制作成为单执行文件的绿色软件。它支持所有类型的文件格式,虚拟化后的软件不释放任何临时文件到您的硬盘,文件模拟过程仅在内存运行。
Enigma virtual box官方链接:https://enigmaprotector.com/cn/downloads.html
进入官网后找到红框部分点击下载即可,不需要注册账号: 
下载后点击安装,安装过程一直next就行,注意勾选创建桌面快捷方式,默认是不创建的。 
安装好后打开可以设置中文语言: 
4.4.2打开安装好的Enigma Virtual Box,点击浏览,找到第三步的目录下的exe文件

4.4.3点击增加,选择递归添加文件,选中demo文件夹点击确定

4.4.4选择目标文件夹后点击确定

4.4.5点击文件选项,选中压缩文件,点击确定

4.4.6最后点击执行封包,等待结束即可。

4.4.7最终生成的文件名和路径,找到该文件双击打开测试是否正常

至此整个打包过程结束
5 网络编程(TCP UDP)
QT的网络编程:网络编程有TCP和UDP。
5.1TCP协议
TCP编程需要用到俩个类:QTcpServer和QTcpSocket
查找帮助可知都需要添加network
5.1.1服务器设计

#include "widget.h"
#include "ui_widget.h"
// 构造函数,初始化Widget对象
Widget::Widget(QWidget* parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); // 设置UI
tcpServer = new QTcpServer(this); // 创建一个新的QTcpServer对象
tcpSocket = new QTcpSocket(this); // 创建一个新的QTcpSocket对象
// 连接信号和槽,当有新的连接时调用newConnection_Slot槽函数
connect(tcpServer, SIGNAL(newConnection()), this, SLOT(newConnection_Slot()));
}
// 槽函数,当有新的连接时调用
void Widget::newConnection_Slot()
{
tcpSocket = tcpServer->nextPendingConnection(); // 获取下一个挂起的连接
// 连接信号和槽,当有数据可读时调用readyRead_Slot槽函数
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
}
// 槽函数,当有数据可读时调用
void Widget::readyRead_Slot()
{
// 将读取到的数据追加到recvTextEdit文本编辑器中
ui->recvTextEdit->appendPlainText(tcpSocket->readAll());
}
// 析构函数,清理资源
Widget::~Widget()
{
delete ui; // 删除UI对象
}
// 槽函数,当打开按钮被点击时调用
void Widget::on_openBt_clicked()
{
// 监听所有IP地址和端口,端口号从portEdit文本框中获取并转换为无符号整数
tcpServer->listen(QHostAddress::Any, ui->portEdit->text().toUInt());
}
// 槽函数,当关闭按钮被点击时调用
void Widget::on_closeBt_clicked()
{
tcpServer->close(); // 关闭服务器
}
// 槽函数,当发送按钮被点击时调用
void Widget::on_sendBt_clicked()
{
// 发送sendEdit文本框中的数据,数据转换为本地8位字节数组
// 发送前需要转换一下,转为QByteString类型字符串,并且再转换成char*发送,防止乱码
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
}
5.2.2客户端设计

#include "widget.h"
#include "ui_widget.h"
// 构造函数,初始化Widget对象
Widget::Widget(QWidget* parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); // 设置UI
tcpSocket = new QTcpSocket(this); // 创建一个新的QTcpSocket对象
}
// 析构函数,清理资源
Widget::~Widget()
{
delete ui; // 删除UI对象
}
// 槽函数,当连接成功时调用
void Widget::connected_Slot()
{
// 连接信号和槽,当有数据可读时调用readyRead_Slot槽函数
connect(tcpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
}
// 槽函数,当有数据可读时调用
void Widget::readyRead_Slot()
{
// 将读取到的数据追加到recvTextEdit文本编辑器中
ui->recvTextEdit->appendPlainText(tcpSocket->readAll());
}
// 槽函数,当打开按钮被点击时调用
void Widget::on_openBt_clicked()
{
// 连接到主机,IP地址和端口号分别从ipEdit和portEdit文本框中获取并转换
tcpSocket->connectToHost(ui->ipEdit->text(), ui->portEdit->text().toUInt());
// 连接信号和槽,当连接成功时调用connected_Slot槽函数
connect(tcpSocket, SIGNAL(connected()), this, SLOT(connected_Slot()));
}
// 槽函数,当关闭按钮被点击时调用
void Widget::on_closeBt_clicked()
{
tcpSocket->close(); // 关闭连接
}
// 槽函数,当发送按钮被点击时调用
void Widget::on_sendBt_clicked()
{
// 发送sendEdit文本框中的数据,数据转换为本地8位字节数组
tcpSocket->write(ui->sendEdit->text().toLocal8Bit().data());
}
5.2UDP协议
udp不分客户端和服务器,只需要使用一个类QUdpSocket
#include "widget.h"
#include "ui_widget.h"
// 构造函数,初始化Widget对象
Widget::Widget(QWidget* parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this); // 设置UI
udpSocket = new QUdpSocket(this); // 创建一个新的QUdpSocket对象
// 设置按钮的初始状态
ui->openBt->setEnabled(true);
ui->closBt->setEnabled(false);
ui->sendBt->setEnabled(false);
}
// 析构函数,清理资源
Widget::~Widget()
{
delete ui; // 删除UI对象
}
// 槽函数,当有数据可读时调用
void Widget::readyRead_Slot()
{
while (udpSocket->hasPendingDatagrams()) // 当有挂起的数据报时
{
QByteArray array;
array.resize(udpSocket->pendingDatagramSize()); // 调整数组大小以适应数据报
udpSocket->readDatagram(array.data(), array.size()); // 读取数据报
QString buf = array.data(); // 将数据转换为QString
ui->recvEdit->appendPlainText(buf); // 将数据追加到recvEdit文本编辑器中
}
}
// 槽函数,当打开按钮被点击时调用
void Widget::on_openBt_clicked()
{
// 绑定本地端口,成功则启用相关按钮
if(udpSocket->bind(ui->localPort->text().toUInt()) == true)
{
ui->openBt->setEnabled(false);
ui->closBt->setEnabled(true);
ui->sendBt->setEnabled(true);
}
// 连接信号和槽,当有数据可读时调用readyRead_Slot槽函数
connect(udpSocket, SIGNAL(readyRead()), this, SLOT(readyRead_Slot()));
}
// 槽函数,当关闭按钮被点击时调用
void Widget::on_closBt_clicked()
{
udpSocket->close(); // 关闭UDP连接
// 重置按钮的状态
ui->openBt->setEnabled(true);
ui->closBt->setEnabled(false);
ui->sendBt->setEnabled(false);
}
// 槽函数,当发送按钮被点击时调用
void Widget::on_sendBt_clicked()
{
QHostAddress address;
address.setAddress(ui->aimIp->text()); // 设置目标IP地址
quint16 port = ui->aimPort->text().toUInt(); // 获取目标端口号
QString sendbuff = ui->sendEdit->text(); // 获取发送数据
// 发送数据报
udpSocket->writeDatagram(sendbuff.toLocal8Bit().data(), sendbuff.length(), address, port);
}
6 时间编程
qtime:qt的时间类
qtimer:qt的定时类

#include "widget.h"
#include "ui_widget.h"
Widget::Widget(QWidget* parent) :
QWidget(parent),
ui(new Ui::Widget)
{
ui->setupUi(this);
connect( & timer, SIGNAL(timeout()), this, SLOT(timeout_Slot()));
time.setHMS(0, 0, 0, 0);
ui->showTime->setText(time.toString("hh:mm:ss:zzz"));
}
Widget::~Widget()
{
delete ui;
}
void Widget::timeout_Slot()
{
//qDebug() << "timeout_Slot";
time = time.addMSecs(30);
ui->showTime->setText(time.toString("hh:mm:ss:zzz"));
}
void Widget::on_starBt_clicked()
{
//timer.setSingleShot(true);//只计时一次
timer.start(30);
}
void Widget::on_closBt_clicked()
{
timer.stop();
}
void Widget::on_resetBt_clicked()
{
timer.stop();
time.setHMS(0, 0, 0, 0);
ui->showTime->setText(time.toString("hh:mm:ss:zzz"));
}
static int i = 0;
void Widget::on_bitBt_clicked()
{
QString temp;
i = i + 1;
temp.sprintf("%d--->", i);
ui->bitTime->append(temp);
ui->bitTime->append(time.toString("hh:mm:ss:zzz"));
}
void Widget::on_clearBt_clicked()
{
ui->bitTime->clear();
i = 0;
}
评论 (0)