极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战

文章目录

  • 前言
  • 一、成果先行
  • 二、下载安装
    • 1.安装QT
  • 三、项目开发实战
    • 1.创建新项目
    • 2.UI设计
    • 3.编写widget.h头文件
    • 4.编写widget.cpp源文件
  • 四、编译运行
  • 五、项目打包
    • 1.编译发布版
    • 2.绿色版打包
    • 3.安装版打包
  • 总结


前言

C语言学了这么久是否还跟我一样对着黑窗口体验与printf的极致交流,学了Python后似乎忘了C/C++也能开发图形化界面,直到揭开Qt神秘的面纱,才有相见恨晚的感觉。在此之前,都用Python开发上位机软件,语言简洁精炼,入门简单高效。但世界总是公平的,有舍就有的,有好处必然有坏处。其一,多次碰到程序卡顿的情况。其二,使用串口时若没有在退出前关闭,就会一直占用。其三,打包出来的可执行程序体积太大。以上三宗罪并不是不可解决,但纠其根本,在于脚本语言本身没有低级语言的稳定性和速度。个人开发者倒是无所谓,对于工程实践更多需要是稳定和流畅。

难学的东西学会了肯定是有好处的,于是开始探索C/C++开发图像化界面的道路。了解了MFC,是微软公司提供的一个类库,只针对Windows平台开发可视化界面,许多windows程序都是由它开发,入门了一两天,用起来还是挺痛苦的。知道被Qt吸引,以其跨平台,文档丰富而完善,入门轻松高效,界面优美大方等优势,无可挑剔。

不过对于初学者,C语言学得多,C++部分看得懂,学起来还是有一些门槛的。本文基于三天入门过程中走过的弯路,以先成功后学习的理念,总结出一篇完整开发串口调试助手的简单实践,让初学者少走弯路,快速体验完整开发流程,再去深入了解或研究其他高深内容。


提示:之所以写这篇文章,也是因为看了许多其他作者的文章大受益处,分享带来共赢

一、成果先行

极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第1张图片
此串口调试助手功能还是比较完善的,使用起来丝毫不卡顿,启动速度也相当优秀,可打包成绿色版和安装版,用来代替市面上的串口调试助手是个不错的选择。可最重要的是有了开发技术,随意添加任何其他功能或对界面进行优化。给它取名为QComTool

二、下载安装

1.安装QT

从官网下载安装包:https://download.qt.io/archive/qt/5.14/5.14.2/ 本文使用5.14.2版本,其他版本或许略有不同,尽量别下最新版,用最新版会走更多弯路。下载后直接运行安装。刚进入安装程序会要求输入注册账户,如果闲麻烦可以先断网,再运行安装程序,会自动跳过这一步,再去联网即可。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第2张图片
组件选择需特别注意,本文只需选择MinGW 7.30 64位系统,用来编译运行,其他组件可以根据需要勾选,由于篇幅限制不展开描述。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第3张图片
之后根据提示一路下一步即可。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第4张图片
安装成功后打开开始菜单栏打开Qt Creator软件,是用于应用程序开发的跨平台IDE。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第5张图片

三、项目开发实战

1.创建新项目

极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第6张图片
选择Qt Widgets应用程序
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第7张图片
设置项目路径和名称
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第8张图片
编译系统默认
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第9张图片
基类选择QWidget
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第10张图片
然后一路下一步。创建成功后,直接Ctrl + R编译运行,或者点击左下角小锤子即可出现空白窗口。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第11张图片

2.UI设计

工程项目目录很简洁,*。pro包含一些配置脚本,一个基类头文件和源文件再加主程序文件。最下面的是设计UI的文件。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第12张图片
打开UI设计文件,可以很方便的通过拖拽方式设计界面,并且配置属性和名称。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第13张图片
先添加三个主体框架,修改属性让边框更清晰,再点击阵列分布自动适应窗口大小并对齐。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第14张图片
其他部分同理,根据需要设计自己的界面,特别注意修改各个控件的名称方便写程序,可在右侧层次结构框架中直接单击修改。设计出以下界面。
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第15张图片
若对这一步有困难,可以直接用记事本打开这个ui文件,复制以下代码,自动生成该界面。


<ui version="4.0">
 <class>Widgetclass>
 <widget class="QWidget" name="Widget">
  <property name="geometry">
   <rect>
    <x>0x>
    <y>0y>
    <width>757width>
    <height>529height>
   rect>
  property>
  <property name="windowTitle">
   <string>Widgetstring>
  property>
  <layout class="QGridLayout" name="gridLayout">
   <item row="0" column="0">
    <widget class="QFrame" name="frame">
     <property name="frameShape">
      <enum>QFrame::Boxenum>
     property>
     <property name="frameShadow">
      <enum>QFrame::Raisedenum>
     property>
     <property name="lineWidth">
      <number>2number>
     property>
     <layout class="QVBoxLayout" name="verticalLayout">
      <item>
       <layout class="QFormLayout" name="formLayout_2">
        <property name="verticalSpacing">
         <number>20number>
        property>
        <item row="0" column="0">
         <widget class="QLabel" name="label">
          <property name="text">
           <string>串口号:string>
          property>
         widget>
        item>
        <item row="0" column="1">
         <widget class="QComboBox" name="comboBox_1"/>
        item>
        <item row="1" column="0">
         <widget class="QLabel" name="label_2">
          <property name="text">
           <string>波特率:string>
          property>
         widget>
        item>
        <item row="1" column="1">
         <widget class="QComboBox" name="comboBox_2"/>
        item>
        <item row="2" column="0">
         <widget class="QLabel" name="label_3">
          <property name="text">
           <string>校验位:string>
          property>
         widget>
        item>
        <item row="2" column="1">
         <widget class="QComboBox" name="comboBox_3"/>
        item>
        <item row="3" column="0">
         <widget class="QLabel" name="label_4">
          <property name="text">
           <string>数据位:string>
          property>
         widget>
        item>
        <item row="3" column="1">
         <widget class="QComboBox" name="comboBox_4"/>
        item>
        <item row="4" column="0">
         <widget class="QLabel" name="label_5">
          <property name="text">
           <string>停止位:string>
          property>
         widget>
        item>
        <item row="4" column="1">
         <widget class="QComboBox" name="comboBox_5"/>
        item>
        <item row="5" column="0">
         <widget class="QLabel" name="label_6">
          <property name="text">
           <string>流控制:string>
          property>
         widget>
        item>
        <item row="5" column="1">
         <widget class="QComboBox" name="comboBox_6"/>
        item>
        <item row="6" column="0">
         <widget class="QLabel" name="label_7">
          <property name="text">
           <string>字编码:string>
          property>
         widget>
        item>
        <item row="6" column="1">
         <widget class="QComboBox" name="comboBox_7"/>
        item>
       layout>
      item>
      <item>
       <widget class="QPushButton" name="Btn_Serial_Open">
        <property name="text">
         <string>打开串口string>
        property>
       widget>
      item>
     layout>
    widget>
   item>
   <item row="0" column="1">
    <widget class="QFrame" name="frame_2">
     <property name="frameShape">
      <enum>QFrame::Boxenum>
     property>
     <property name="frameShadow">
      <enum>QFrame::Raisedenum>
     property>
     <property name="lineWidth">
      <number>2number>
     property>
     <layout class="QVBoxLayout" name="verticalLayout_2">
      <item>
       <widget class="QTextEdit" name="RX_Text">
        <property name="tabChangesFocus">
         <bool>falsebool>
        property>
        <property name="readOnly">
         <bool>truebool>
        property>
       widget>
      item>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout">
        <item>
         <widget class="QPushButton" name="Btn_Clear">
          <property name="text">
           <string>清空所有string>
          property>
          <property name="checkable">
           <bool>falsebool>
          property>
          <property name="autoDefault">
           <bool>falsebool>
          property>
          <property name="default">
           <bool>falsebool>
          property>
          <property name="flat">
           <bool>falsebool>
          property>
         widget>
        item>
        <item>
         <layout class="QHBoxLayout" name="RX_Box">
          <item>
           <widget class="QCheckBox" name="RX_CheckBox_Hex">
            <property name="text">
             <string>Hexstring>
            property>
            <property name="checked">
             <bool>falsebool>
            property>
           widget>
          item>
          <item>
           <widget class="QCheckBox" name="RX_CheckBox_Format">
            <property name="text">
             <string>日志格式string>
            property>
            <property name="checked">
             <bool>truebool>
            property>
           widget>
          item>
         layout>
        item>
       layout>
      item>
     layout>
    widget>
   item>
   <item row="1" column="0" colspan="2">
    <widget class="QFrame" name="frame_Send">
     <property name="frameShape">
      <enum>QFrame::Boxenum>
     property>
     <property name="frameShadow">
      <enum>QFrame::Raisedenum>
     property>
     <property name="lineWidth">
      <number>2number>
     property>
     <layout class="QVBoxLayout" name="verticalLayout_3">
      <item>
       <widget class="QTextEdit" name="TX_Text"/>
      item>
      <item>
       <layout class="QHBoxLayout" name="horizontalLayout_4">
        <item>
         <widget class="QPushButton" name="Btn_Send">
          <property name="text">
           <string>发送string>
          property>
          <property name="checkable">
           <bool>falsebool>
          property>
          <property name="checked">
           <bool>falsebool>
          property>
          <property name="autoDefault">
           <bool>falsebool>
          property>
          <property name="default">
           <bool>falsebool>
          property>
          <property name="flat">
           <bool>falsebool>
          property>
         widget>
        item>
        <item>
         <widget class="QFrame" name="frame_4">
          <property name="frameShape">
           <enum>QFrame::StyledPanelenum>
          property>
          <property name="frameShadow">
           <enum>QFrame::Raisedenum>
          property>
          <layout class="QHBoxLayout" name="horizontalLayout_2">
           <item>
            <widget class="QCheckBox" name="Auto_Send">
             <property name="text">
              <string>自动发送string>
             property>
            widget>
           item>
           <item>
            <widget class="QSpinBox" name="Wait_ms">
             <property name="minimum">
              <number>1number>
             property>
             <property name="maximum">
              <number>10000number>
             property>
             <property name="value">
              <number>100number>
             property>
            widget>
           item>
           <item>
            <widget class="QLabel" name="label_9">
             <property name="text">
              <string>msstring>
             property>
            widget>
           item>
          layout>
         widget>
        item>
        <item>
         <layout class="QHBoxLayout" name="TX_Box">
          <item>
           <widget class="QCheckBox" name="TX_CheckBox_Hex">
            <property name="text">
             <string>Hexstring>
            property>
           widget>
          item>
          <item>
           <widget class="QLabel" name="TX_Num">
            <property name="text">
             <string>已发送:0string>
            property>
           widget>
          item>
          <item>
           <widget class="QLabel" name="RX_Num">
            <property name="text">
             <string>已接收:0string>
            property>
           widget>
          item>
          <item>
           <widget class="QPushButton" name="Btn_Clear_Num">
            <property name="text">
             <string>清零string>
            property>
            <property name="checkable">
             <bool>falsebool>
            property>
            <property name="autoDefault">
             <bool>falsebool>
            property>
            <property name="default">
             <bool>falsebool>
            property>
            <property name="flat">
             <bool>falsebool>
            property>
           widget>
          item>
         layout>
        item>
       layout>
      item>
     layout>
    widget>
   item>
  layout>
 widget>
 <resources/>
 <connections/>
ui>

3.编写widget.h头文件

widget.h文件中加入以下方法和属性,其中,方法作为自定义槽函数,信号和槽是Qt中的核心概念,通俗的讲就是一个控件状态的改变(如按钮被点击)会发出特定信号,通过connect函数将信号连接到指定的槽函数中,有信号就能触发槽函数运行。

#ifndef WIDGET_H
#define WIDGET_H

#include 
#include 
#include 

QT_BEGIN_NAMESPACE
namespace Ui { class Widget; }
QT_END_NAMESPACE

class Widget : public QWidget
{
    Q_OBJECT
public:
    Widget(QWidget *parent = nullptr);
    ~Widget();
    QSerialPort Serial;
    QTimer time;
    quint64 RX_Cnt;
    quint64 TX_Cnt;
    void Set_TX_Hex(bool checked);
    void Check_TX_Text();
    void Clear_Num();
    void ComboBox_AddItems();
    void Serial_Receive();
    void Serial_Ready_Send();
    void Serial_Send();
    void Serial_Tab();
    bool Serial_Open();
    bool Serial_Close();
    void OnTimeOut();


private:
    Ui::Widget *ui;

};
#endif // WIDGET_H

这里报错,不存在串口模块
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第16张图片
需要在pro文件中添加这个模块
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第17张图片

4.编写widget.cpp源文件

这里添加函数实现以及配置各个信号与槽相连接

#include "widget.h"
#include "ui_widget.h"
#include 
#include 
#include 
#include 
#include 

Widget::Widget(QWidget *parent)
    : QWidget(parent)
    , ui(new Ui::Widget)
{
    ui->setupUi(this);
    this->setWindowTitle("QComTool");
    ui->frame_Send->setMaximumHeight(300);

    RX_Cnt = TX_Cnt = 0;//计数清零
    ui->Btn_Send->setEnabled(false);

    //添加项目
    ComboBox_AddItems();
    //连接信号槽 当下位机发送数据QSerialPor会发送readyRead信号,定义槽Serial_Receive解析数据
    connect(&Serial,&QSerialPort::readyRead,this,&Widget::Serial_Receive);
    //打开串口按钮
    connect(ui->Btn_Serial_Open,&QPushButton::clicked,this,&Widget::Serial_Tab);
    //发送数据按钮
    connect(ui->Btn_Send,&QPushButton::clicked,this,&Widget::Serial_Ready_Send);
    //清空接收按钮
    connect(ui->Btn_Clear,&QPushButton::clicked, ui->RX_Text,&QTextEdit::clear);
    //数据清零按钮
    connect(ui->Btn_Clear_Num,&QPushButton::clicked,this,&Widget::Clear_Num);
    //切换发送为Hex
    connect(ui->TX_CheckBox_Hex,  &QCheckBox::toggled, this,&Widget::Set_TX_Hex);
    //发送框文本改变
    connect(ui->TX_Text,&QTextEdit::textChanged,this,&Widget::Check_TX_Text);
    //自动发送
    connect(&time,&QTimer::timeout,this,&Widget::Serial_Send);
    //自动发送的循环时间
    connect(ui->Wait_ms, QOverload<int>::of(&QSpinBox::valueChanged),
          [=](int i){time.setInterval(i);});//匿名函数
}

Widget::~Widget()
{
    delete ui;
}
//切换发送为Hex
void Widget::Set_TX_Hex(bool checked)
{
    if (checked)
    {
        //编码格式
        QByteArray code_name;
        code_name.append(ui->comboBox_7->currentText());
        QTextCodec *codec = QTextCodec::codecForName(code_name);
        //数据转换
        QByteArray Encoded_data = codec->fromUnicode(ui->TX_Text->toPlainText());
        QString ret(Encoded_data.toHex().toUpper());
        if(ret.length()%2 == 1)
        {
            ret.insert(ret.length()-1,"0");
        }
        int len = ret.length()/2;
        for(int i=0;i<len;i++)
        {
            ret.insert(2*i+i+2," ");
        }
        ui->TX_Text->setText(ret);
    }
    else
    {
        QString ret = ui->TX_Text->toPlainText();
        ret = ret.toUpper();//全部大写
        ret.remove(QRegExp("[^A-F0-9]"));//正则匹配删除非法字符
        QByteArray Data_Hex;
        Data_Hex.append(ret);
        QByteArray Data_Ascii = QByteArray::fromHex(Data_Hex);
        //编码格式
        QByteArray code_name;
        code_name.append(ui->comboBox_7->currentText());
        QTextCodec *codec = QTextCodec::codecForName(code_name);
        //数据转换
        QString Unicode_data = codec->toUnicode(Data_Ascii);
        ui->TX_Text->setText(Unicode_data);
    }
}
//校验发送框字符是否非法
void Widget::Check_TX_Text()
{
    if(ui->TX_CheckBox_Hex->isChecked())
    {
        QString ret1 = ui->TX_Text->toPlainText(),ret2;
        ret2 = ret1.toUpper();
        ret1.remove(QRegExp("[A-F0-9][A-F0-9]\\s"));//先去除合法Hex字符
        if(ret1.length() > 1)
        {
            ret2.remove(QRegExp("[^A-F0-9]"));//删除非法字符
            if(ret2.length()%2 == 1)
            {
                ret2.insert(ret2.length()-1,"0");
            }
            int len = ret2.length()/2;
            for(int i=0;i<len;i++)
            {
                ret2.insert(2*i+i+2," ");
            }
            ui->TX_Text->setText(ret2);
            ui->TX_Text->moveCursor(QTextCursor::End, QTextCursor::MoveAnchor);
        }
    }
}
//下拉列表框添加项目
void Widget::ComboBox_AddItems()
{
    QMetaEnum metaEnum;
    QStringList strList;
    //comboBox_1 可用串口
    foreach(const QSerialPortInfo &info,QSerialPortInfo::availablePorts())
    {
        ui->comboBox_1->addItem(info.portName());
    }
    //comboBox_2 波特率
    metaEnum = QMetaEnum::fromType<QSerialPort::BaudRate>();
    for (int i = 0; i < metaEnum.keyCount()-1; i++)
    {
        ui->comboBox_2->addItem(QString::number(metaEnum.value(i)));
    }
    ui->comboBox_2->setCurrentText(QString::number(QSerialPort::Baud115200));
    //comboBox_3 校验位
    strList<<"无"<<"奇校验"<<"偶校验"<<"为0"<<"为1";
    ui->comboBox_3->addItems(strList);
    strList.clear();
    //comboBox_4 数据位
    metaEnum = QMetaEnum::fromType<QSerialPort::DataBits>();
    for (int i = 0; i < metaEnum.keyCount()-1; i++)
    {
        ui->comboBox_4->addItem(QString::number(metaEnum.value(i)));
    }
    ui->comboBox_4->setCurrentText(QString::number(QSerialPort::Data8));
    //comboBox_5 停止位
    strList<<"1"<<"1.5"<<"2";
    ui->comboBox_5->addItems(strList);
    strList.clear();
    //comboBox_6 流控
    strList<<"无"<<"硬件"<<"软件";
    ui->comboBox_6->addItems(strList);
    strList.clear();
    //字符编码格式
    strList<<"GBK"<<"UTF-8";
    ui->comboBox_7->addItems(strList);
    strList.clear();
}
//数据清零
void Widget::Clear_Num()
{
    RX_Cnt = TX_Cnt = 0;
    ui->RX_Num->setText("已接收:"+QString::number(RX_Cnt));
    ui->TX_Num->setText("已发送:"+QString::number(TX_Cnt));
}
//接收数据
void Widget::Serial_Receive()
{
    QByteArray data = Serial.readAll();
    RX_Cnt += data.length();
    ui->RX_Num->setText("已接收:"+QString::number(RX_Cnt));
    if(ui->RX_CheckBox_Format->isChecked())//添加日志
    {
        QDateTime time = QDateTime::currentDateTime();
        QString current_date = time.toString("\n【yyyy.MM.dd hh:mm:ss.zzz 接收】\n");
        ui->RX_Text->insertPlainText(current_date);
    }
    if(ui->RX_CheckBox_Hex->isChecked())//Hex模式
    {
        uchar temp;
        QString Hex;
        for (int i = 0; i < data.size(); i++)
        {
            temp = data.at(i);
            if(temp < 0x10)Hex += "0";
            Hex += QString::number(temp,16).toUpper()+" ";
        }
        ui->RX_Text->insertPlainText(Hex);
    }
    else
    {
        //编码格式
        QByteArray code_name;
        code_name.append(ui->comboBox_7->currentText());
        QTextCodec *codec = QTextCodec::codecForName(code_name);
        QString Unicode_data = codec->toUnicode(data);
        ui->RX_Text->insertPlainText(Unicode_data);
    }
    ui->RX_Text->moveCursor(QTextCursor::End);
}
//发送数据准备工作
void Widget::Serial_Ready_Send()
{
    if(ui->Auto_Send->isChecked())//自动发送使能
    {
        if(ui->Btn_Send->text().operator==("发送"))//开始发送
        {
            ui->Btn_Send->setText("停止发送");
            time.setInterval(ui->Wait_ms->value());//循环时间
            time.start();
        }
        else
        {
            ui->Btn_Send->setText("发送");
            time.stop();
        }
    }
    else
    {
        Serial_Send();
    }
}
//发送数据
void Widget::Serial_Send()
{
    if(ui->Auto_Send->isChecked() == false &&
       ui->Btn_Send->text().operator==("停止发送"))//自动发送使能
    {
        ui->Btn_Send->setText("发送");
        time.stop();
        return;
    }
    QByteArray Data_QByteArray;
    if(ui->TX_CheckBox_Hex->isChecked())//Hex格式发送
    {
        QString ret = ui->TX_Text->toPlainText();
        ret = ret.toUpper();//全部大写
        ret.remove(QRegExp("[^A-F0-9]"));//正则匹配删除非法字符
        QByteArray Hex_Srting;
        Hex_Srting.append(ret);
        Data_QByteArray = QByteArray::fromHex(Hex_Srting);
    }
    else//字符串格式发送
    {
        //编码格式
        QByteArray code_name;
        code_name.append(ui->comboBox_7->currentText());
        QTextCodec *codec = QTextCodec::codecForName(code_name);
        //数据发送
        Data_QByteArray = codec->fromUnicode(ui->TX_Text->toPlainText());
    }
    if(Data_QByteArray.length() > 0)
    {
        if(Serial.write(Data_QByteArray) >= 0)
        {
            if(ui->RX_CheckBox_Format->isChecked())//如果开启日志模式
            {
                QDateTime time = QDateTime::currentDateTime();
                QString current_date = time.toString("\n【yyyy.MM.dd hh:mm:ss.zzz 发送】\n");
                current_date += ui->TX_Text->toPlainText();
                ui->RX_Text->insertPlainText(current_date);
                ui->RX_Text->moveCursor(QTextCursor::End);
            }
            TX_Cnt += Data_QByteArray.length();
            ui->TX_Num->setText("已发送:"+QString::number(TX_Cnt));
        }
        else
        {
            QMessageBox::critical(this, tr("错误"), tr("串口发送失败"));
        }

    }
}
//切换串口状态
void Widget::Serial_Tab()
{
    if(ui->Btn_Serial_Open->text().operator==("打开串口"))
    {
        if(Serial_Open())
        {
            ui->Btn_Serial_Open->setText("关闭串口");
            ui->Btn_Send->setEnabled(true);
            ui->Btn_Send->setText("发送");
            time.stop();
        }
        else
        {
            QMessageBox::critical(this, tr("错误"), tr("串口打开失败"));
        }
    }
    else
    {
        if(Serial_Close())
        {
            ui->Btn_Serial_Open->setText("打开串口");
            ui->Btn_Send->setEnabled(false);
        }
    }

}
//打开串口
bool Widget::Serial_Open()
{
    Serial.setParent(this);
    QString PortName = ui->comboBox_1->currentText();
    QString Temp_String;
    //这样我们就获取到 可用的串口名字了
    Serial.setPortName(PortName);
    if(Serial.isOpen())//如果串口已经打开了 先给他关闭了
    {
        Serial.clear();
        Serial.close();
    }
    if(Serial.open(QIODevice::ReadWrite))//用ReadWrite 的模式尝试打开串口
    {
        //波特率设置
        Serial.setBaudRate(ui->comboBox_2->currentText().toInt(),QSerialPort::AllDirections);//设置波特率和读写方向
        //校验位设置
        Temp_String = ui->comboBox_3->currentText();
        QSerialPort::Parity Serial_Parity;
        if(Temp_String.operator == ("无" ))
            Serial_Parity = QSerialPort::NoParity;
        else if (Temp_String.operator == ("奇校验"))
            Serial_Parity = QSerialPort::EvenParity;
        else if (Temp_String.operator == ("偶校验"))
            Serial_Parity = QSerialPort::OddParity;
        else if (Temp_String.operator == ("为0"))
            Serial_Parity = QSerialPort::SpaceParity;
        else if (Temp_String.operator == ("为1"))
            Serial_Parity = QSerialPort::MarkParity;
        else
            Serial_Parity = QSerialPort::UnknownParity;
        Serial.setParity(Serial_Parity);
        //数据位设置
        Temp_String = ui->comboBox_4->currentText();
        QSerialPort::DataBits Serial_DataBits;
        if(Temp_String.operator == ("5"))
            Serial_DataBits = QSerialPort::Data5;
        else if (Temp_String.operator == ("6"))
            Serial_DataBits = QSerialPort::Data6;
        else if (Temp_String.operator == ("7"))
            Serial_DataBits = QSerialPort::Data7;
        else if (Temp_String.operator == ("8"))
            Serial_DataBits = QSerialPort::Data8;
        else
            Serial_DataBits = QSerialPort::UnknownDataBits;
        Serial.setDataBits(Serial_DataBits);		//数据位
        //停止位
        Temp_String = ui->comboBox_5->currentText();
        QSerialPort::StopBits Serial_StopBits;
        if(Temp_String.operator == ("1"))
            Serial_StopBits = QSerialPort::OneStop;
        else if (Temp_String.operator == ("1.5"))
            Serial_StopBits = QSerialPort::OneAndHalfStop;
        else if (Temp_String.operator == ("2"))
            Serial_StopBits = QSerialPort::TwoStop;
        else
            Serial_StopBits = QSerialPort::UnknownStopBits;
        Serial.setStopBits(Serial_StopBits);
        //流控制
        Temp_String = ui->comboBox_6->currentText();
        QSerialPort::FlowControl Serial_FlowControl;
        if(Temp_String.operator == ("无"))
            Serial_FlowControl = QSerialPort::NoFlowControl;
        else if (Temp_String.operator == ("硬件"))
            Serial_FlowControl = QSerialPort::HardwareControl;
        else if (Temp_String.operator == ("软件"))
            Serial_FlowControl = QSerialPort::SoftwareControl;
        else
            Serial_FlowControl = QSerialPort::UnknownFlowControl;
        Serial.setFlowControl(Serial_FlowControl);
        return true;
    }
    return false;
}
//关闭串口
bool Widget::Serial_Close()
{
    if(Serial.isOpen())//关闭旧串口
    {
        Serial.clear();
        Serial.close();
        return true;
    }
    return false;
}

四、编译运行

到这里可能还有一些列报错,不过没关系,只要按照以上步骤,再点击编译后就不会报错。先给它添加一个图标,可将以下图片通过这个网站https://www.aconvert.com/cn/icon/jpg-to-ico/生成ICO图标,命名为QComTool.ico放到项目文件夹中,
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第18张图片
再Pro文件中加入这一行代码添加图标资源RC_ICONS = QComTool.ico

极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第19张图片
Ctrl+R编译运行:
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第20张图片

五、项目打包

1.编译发布版

选择发布版进行编译,同样Ctrl+R
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第21张图片
于是正常了发布版程序
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第22张图片
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第23张图片
但此时这个程序还不能运行,需要链接动态库文件,也就是传说中的dll.

2.绿色版打包

新建一个目录,命名为QComTool
将exe文件放到这个目录中
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第24张图片

在开始菜单栏中找到 MinGW
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第25张图片
运行代码

windeployqt.exe 文件绝对路径\QComTool.exe

程序会自动将所有动态链接库复制到这个目录中
极速入门体验Qt5软件开发,从安装到打包,少走弯路,Qt入门指南,串口调试助手开发实战_第26张图片
这样就得到了一个绿色版的程序,大功告成,点击exe即可运行。

3.安装版打包

如果还需要打包成安装版,可以使用工具 innosetup-6.2.1.exe 进行打包,官网下载链接:
https://jrsoftware.org/isinfo.php,只需通过这个工具把绿色版整个文件夹打包成安装包程序即可。

总结

通过本文实现了串口调试助手功能,但篇幅限制没有展开描述,相信有C++基础的基本能够看懂程序,更多功能等待探索。

你可能感兴趣的:(c++,qt5,ui,windows)