QT上位机开发

news2024/11/16 12:23:31

目录

  • 前言
  • 一、环境搭建
    • 1.1 IDE下载
    • 1.2 添加环境变量
  • 二、Qt Creator的使用
    • 2.1 快捷键
    • 2.2 创建QT项目
    • 2.3 帮助文档使用
  • 三、Qt信号与槽
    • 3.1 标准信号与槽的使用
    • 3.2 自定义信号与槽
  • 四、Qt控件
    • 4.1 QMainWindow
    • 4.2 按钮
    • 4.3 容器
    • 4.4 窗口
    • 4.5 布局管理
  • 五、SerialPort
    • 5.1 修改.Pro文件
    • 5.2 修改mainwindow.h头文件
    • 5.3 修改mainwindow.cpp源文件
    • 5.4 效果
  • 六、QT程序发布与打包
    • 6.1 添加图标
    • 6.2 生成Release版程序
    • 6.3 添加动态库
    • 6.4 Qt程序打包
      • 6.4.1 打包成单文件版
      • 6.4.2 打包成可安装版本


前言

  本文只介绍Windows的QT上位机开发,以串口为例。本文的QT版本为5.15。

  • C++基础见链接:https://blog.csdn.net/weixin_44567668/article/details/126098388

一、环境搭建

1.1 IDE下载

  • Qt官方下载地址:https://www.qt.io/download#eval-form-modal
    在这里插入图片描述
    注意:这里下载的在线安装器,必须先下载然后根据提示注册,才能称为开源用户,否则为商业用户。

  也可以使用国内服务器平台下载:

  • 中国科学技术大学:http://mirrors.ustc.edu.cn/qtproject/
  • 清华大学:https://mirrors.tuna.tsinghua.edu.cn/qt/

1.2 添加环境变量

  安装教程可以百度,安装好之后将以下三个添加进来,需要重启才能生效
在这里插入图片描述

二、Qt Creator的使用

2.1 快捷键

快捷键作用
Ctrl + Space代码自动完成
Ctrl + I格式化文本
F2跳转到下一个错误或警告
Shift + F2跳转到上一个错误或警告
Ctrl + /注释或取消注释所选行
Ctrl + K跳转到定义
Ctrl + E打开最近的文件
Ctrl + Shift + E打开最近的项目
Ctrl + F12显示当前文件的类或函数列表
F4跳转到包含光标所在文本的定义
Ctrl + Shift + F4返回上一个查看的位置
Ctrl + R构建项目。
Ctrl + B构建并运行项目。
Ctrl + D调试项目。
Ctrl + Shift + B构建所有项目。
Ctrl + T运行单元测试。
F5重新运行应用程序。
F1帮助文档

2.2 创建QT项目

  创建基于窗口的Qt应用程序,然后输入项目名称与目录再下一步
在这里插入图片描述
  选择构建脚本,这边选择qmake
在这里插入图片描述
在这里插入图片描述
  这里默认就好,其中Base class是基类,有以下三个选项:

  • QMainWindow:主窗口类,主窗口具有主菜单栏、工具栏和状态栏
  • QWidget:是可视界面类的基类,也就是说QMainWindow类也是由QWidget继承封装而来。一般嵌入式里用
  • QDialog:对话框类,建立一个对话框界面

  直接下一步到构建套件Kit里,选择对应的编译器
在这里插入图片描述
  最后直接完成就可以生成初始工程
在这里插入图片描述
  项目文件介绍:

  • 项目文件.pro:是项目管理文件,当加入了文件或者删除了文件,Qt Creator 会自动修改这个文件
  • Header头文件分组:存放的是项目内所有的头文件*.h
  • Source源文件分组:这个节点下存放的是项目内的所有 C++源码文件*.cpp。main是主函数,mainwindow.cpp是窗口界面对应的类的源文件
  • Forms界面文件分组:这个节点下是存放项目内所有界面文件.ui。.ui文件由XML语言描述组成,编译时会生成相应的cpp文件,一般情况下不需要在xml格式下对这个文件进行编辑

  双击mainwindow.ui,进入“Ui 设计器”页面,拖动Label控件,就可以输入简单文本,这里我们已经完成显示“Hello World!”的设计了。
在这里插入图片描述
  回到编辑界面,点击编译,就可以生成一个简单UI
在这里插入图片描述

2.3 帮助文档使用

  这边以QPushButton为例,在帮助里搜索对应的类
在这里插入图片描述
  可以查看PropertiesPublic Functions这个标题下的属性和函数,点击Inherits可以查看父类的信息
在这里插入图片描述
  最后可以使用快捷键Alt + ←返回到上一级,或者Alt + →进入下一级

三、Qt信号与槽

  • 信号(Signal):就是在特定情况下被发射的事件,例如 PushButton 最常见的信号就是鼠标单击时发射的 clicked() 信号,简而言之就是输入激励
  • 槽(Slot):就是对信号响应的函数,职责就是对Qt框架中产生的信号进行处理

3.1 标准信号与槽的使用

  标准信号与槽就是指QT自带信号与槽,例如PushButton最常见的信号就是鼠标单击时发射的 clicked() 信号。信号与槽关联是用QObject::connect()函数实现的,connect()是QObject类的一个静态函数,而QObject是所有Qt类的基类,通过帮助可以查看函数使用
在这里插入图片描述
  功能简单只需要修改main.cpp文件

#include <QApplication>
#include <QPushButton>
#include <QLineEdit>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    
    //点击按钮
    QPushButton *button = new QPushButton("Click Me");
    QObject::connect(button, &QPushButton::clicked, [=]() {
        qInfo() << "Button Clicked!";
    });
    button->show();
    return a.exec();
}

  效果如下,敲击按钮可以打印输出
在这里插入图片描述

3.2 自定义信号与槽

  自定义信号可以更好的对控件进行统一管理

  1. 创建信号与槽
      新建一个不带ui的项目(取消勾选ui),主函数文件main.cpp可以不动,在mainwindow.h头文件里添加函数声明,有以下注意点:
  • 在使用信号与槽的类中,必须在类的定义中加入宏Q_OBJECT
  • 信号需要使用signals关键字进行声明
  • 声明的槽函数必须是无返回值类型 void,和无需参数
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QPushButton>

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

signals:
    /* 声明一个信号,只需声明,无需定义 */
    void pushButtonTextChanged();

public slots:
    /* 声明一个槽函数 */
    void changeButtonText();

    /* 声明按钮点击的槽函数 */
    void pushButtonClicked();

private:
    /* 声明一个对象pushButton */
    QPushButton *pushButton;
};
#endif // MAINWINDOW_H
  1. 信号与槽的实现
      在mianwindow.cpp里实现槽函数的定义,有以下注意点:
  • 使用connect()连接信号与槽,connect()是QObject类的一个静态函数,而QObject是所有Qt类的基类,在实际调用时可以忽略前面的限定符
  • 习惯性在信号函数前加关键字: emit表示显示的声明一下信号要被发射了,可以省略不写,没有特殊含义
  • 因为我们pushButtonClicked()是本类里定义的槽,所以用this来接收
#include "mainwindow.h"

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /* 设置窗体的宽为800,高为480 */
    this->resize(800,480);

    /* 实例化pushButton对象 */
    pushButton = new QPushButton(this);

    /* 调用setText()方法设定按钮的文本 */
    pushButton->setText("我是一个按钮");

    /* 信号与槽连接 */
    connect(pushButton, SIGNAL(clicked()), this, SLOT(pushButtonClicked()));
    connect(this, SIGNAL(pushButtonTextChanged()), this, SLOT(changeButtonText()));
}

MainWindow::~MainWindow() {}

/* 实现按钮点击槽函数 */
void MainWindow::pushButtonClicked()
{
    /* 使用emit发送信号 */
    emit pushButtonTextChanged();
}

/* 实现按钮文本改变的槽函数 */
void MainWindow::changeButtonText()
{
    /* 在槽函数里改变按钮的文本 */
    pushButton->setText("被点击了!");
}

  效果就是被点击后切换按钮文本
在这里插入图片描述

四、Qt控件

4.1 QMainWindow

  QMainWindow提供了用于构建应用程序用户界面的框架:

  • 菜单栏(Menu Bar)QMenuBar对象用于创建菜单栏,菜单栏通常包含一个或多个菜单,每个菜单包含若干个菜单项。
  • 工具栏(Tool Bar)QToolBar对象用于创建工具栏,工具栏通常包含一组快捷操作按钮,用于执行常用的功能。
  • 状态栏(Status Bar)QStatusBar对象用于创建状态栏,用于显示应用程序的状态信息、提示信息等。
  • 中央部件(Central Widget): 通常是一个自定义的QWidget派生类,作为主窗口的中央区域,用于放置应用程序的主要内容。centralWidget支持支持文档-视图架构,可以通过多文档界面(MDI)或单文档界面(SDI)的方式管理多个文档。
  • Dock窗口(Dock Widgets)QDockWidget对象用于创建可停靠的面板,用户可以拖动和停靠这些面板。

在这里插入图片描述

  1. 创建菜单栏
      首先在最上方添加菜单项,然后新建菜单列表
    在这里插入图片描述
      将菜单列表托上去就可以添加,直接添加只能添加英文
    在这里插入图片描述
  2. 创建工具栏
      右击添加工具栏,然后可以使用同样的方式直接拖动
    在这里插入图片描述
  3. 状态栏
      状态栏是一个用于显示应用程序状态信息、提示信息和用户交互的底部区域。状态栏通常用于向用户提供反馈、进度信息或一般性的应用程序状态,可以使用statusBar()函数来获取当前的状态栏对象
QLabel *statusLabel = new QLabel("Status Label", this);
statusBar()->addPermanentWidget(statusLabel);
  1. 停靠窗口
      拖拽控件到ui里,右侧可以看到相应的对象与类,选中后在右下角属性对其修改
    在这里插入图片描述

4.2 按钮

  首先打开ui设计界面,可以从左侧过滤器里找到Button
在这里插入图片描述

  • QPushButton:下压按钮,继承QAbstractButton类,通常用于执行命令或触发事件,上一小节使用过
  • QToolButton:工具按钮,继承QAbstractButton类。是一种用于命令或者选项的可以快速访问的按钮,通常在ToolBar里面。工具按钮通常显示的是图标,而不是文本标签。ToolButton支持自动浮起。在自动浮起模式中,按钮只有在鼠标指向它的时候才绘制三维的框架。
  • QRadioButton:选择按钮,继承QAbstractButton类。RadioButton 单选按钮(单选框)通常成组出现,用于提供两个或多个互斥选项。
  • QCheckBox:检查框,继承QAbstractButton。复选按钮(复选框)与 RadioButton 的区别是选择模式,单选按钮提供多选一,复选按钮提供多选多。.
  • QCommandLinkButton:命令链接按钮,继承QPushButton。QCommandLinkButton 控件和 RadioButton 相似,都是用于在互斥选项中选择一项。表面上同平面按钮一样,但是 CommandLinkButton 除带有正常的按钮上的文字描述文本外,默认情况下,它也将携带一个箭头图标,表明按下按钮将打开另一个窗口或页面。
  • QDialogButtonBox:对话框按钮,继承QWidget。常用于对话框里自定义按钮,比如“确定”和“取消”按钮。

4.3 容器

在这里插入图片描述

  • Group Box(组框)QGroupBox 继承 QWidget,为构建分组框提供了支持。分组框通常带有一个边框和一个标题栏,作为容器部件来使用,在其中可以布置各种窗口部件。布局时可用作一组控件的容器,但是需要注意的是,内部通常使用布局控件(如 QBoxLayout)进行布局。组框还提供键盘快捷方式,键盘快捷方式将键盘焦点移动到组框的一个子部件。
  • Scroll Area(滚动区域)QScrollArea继承QAbstractScrollArea。滚动区域用于在框架中显示子部件的内容。如果小部件超过框架的大小,视图就会出现滚动条,以便可以查看子小部件的整个区域。
  • Tool Box(工具箱):QToolBox继承QFrame。QToolBox 类提供了一列选项卡小部件项。工具箱是一个小部件,它显示一列选项卡在另一列的上面,当前项显示在当前选项卡的下面。每个选项卡在选项卡列中都有一个索引位置。选项卡的项是 QWidget。
  • Tab Widget(标签小部件)QTabWidget继承 QWidget。abWidget 类提供了一组选项卡(多页面)小部件。QTabWidget主要是用来分页显示的,每一页一个界面,众多界面公用一块区域,节省了界面大小,很方便的为用户显示更多的信息。
  • Stacked WIdget(堆叠小部件)QStackedWidget继承 QFrame。QStackedWidget 类提供了一个小部件堆栈,其中一次只能看到一个小部件,与 QQ 的设置面板类似。QStackedWidget 可用于创建类似于 QTabWidget 提供的用户界面。它是构建在 QStackedLayout 类之上的一个方便的布局小部件。
  • Frame(帧)QFrame继承了QWidget的属性, QFrame 类是有框架的窗口部件的基类,它绘制框架并且调用一个虚函数 drawContents()来填充这个框架。 这种类型的容器窗口可以提供边框, 并且可以设置边框的样式、宽度以及边框的阴影
  • Widget(小部件)QWidget类是所有用户界面对象的基类(如 QLabel 类继承于 QFrame 类,而 QFrame 类又继承于 QWidget 类)。
  • MDI Area(MDI 区域)QMdiArea继承QAbstractScrollArea。QMdiArea 小部件提供一个显示 MDI 窗口的区域。QMdiArea的功能本质上类似于MDI窗口的窗口管理器。大多数复杂的程序,都使用MDI框架
  • Dock Widget(停靠窗体部件)QDockWidget继承QWidget。QDockWidget 类提供了一个小部件,可以停靠在 QMainWindow 内,也可以作为桌面的顶级窗口浮动。

4.4 窗口

在这里插入图片描述

  可以看出窗口部件很多,有输入与显示窗口,这边就挑部分介绍

  • Comb Box(组合框)QComboBox继承 QWidget 类,被 QFontComboBox 类继承。通常用于用户显示选项列表的方法,这种方法占用最少的屏幕空间。
  • Label(标签):QLabel提供了一种用于文本或图像显示的小部件
  • Progress Bar(进度条)QProgressBar继承 QWidget。QProgressBar 小部件提供了一个水平或垂直的进度条。进度条用于向用户显示操作的进度,并向他们确认应用程序仍在运行。
  • Line Edit(单行编辑框)QLineEdit继承QWidget。QLineEdit 小部件是一个单行文本编辑器。行编辑允许用户使用一组有用的编辑函数输入和编辑一行纯文本,包括撤消和重做、剪切和粘贴以及拖放。
  • Text Edit(文本编辑框)QTextEdit继承QAbstractScrollArea,被 QTextBrowser 继承。QTextEdit 是一个高级所见即所得查看器/编辑器,支持使用 html 样式的标记进行 rich text 格式化。
  • Spin Box(数字旋转框)QSpinBox继承 QAbstractSpinBox。用于处理整数和离散值(例如:月份名称)而 QDoubleSpinBox 则用于处理浮点值。他们之间的区别就是处理数据的类型不同,其他功能都基本相同。
  • Time Edit(时间编辑框)QTimeEdit继承 QDateTimeEdit。QTimeEdit 用于编辑时间,而 QDateEdit 用于编辑日期。
  • Date/Time Edit(日期时间编辑框)QDateTimeEdit提供了一个用于编辑日期和时间的小部件。QDateTimeEdit 允许用户使用键盘或箭头键编辑日期,以增加或减少日期和时间值。
  • List Widget(清单控件)QListWidget继承 QListView。QListWidget 类提供了一个基于项的列表小部件
  • QTreeWidget(树形列表框)QTreeWidget继承 QTreeView。QTreeWidget 类提供了一个使用预定义树模型的树视图。

4.5 布局管理

  基本布局管理类包括:QBoxLayout、QGridLayout、QFormLayout 和 QStackedLayout。这些类都从 QLayout 继承而来,它们都来源于 QObject(而不是 QWidget)

  • QBoxLayout提供了水平和垂直的布局管理;
  • QFormLayout提供了将输入部件和标签成组排列的布局管理;
  • QGridLayout提供了网格形式的布局管理;
  • QStackedLayout提供了一组布局后的部件,可以对它们进行分布显示。

  Layouts组里面的 4 种布局,如下:
在这里插入图片描述
  效果如下:
在这里插入图片描述

五、SerialPort

  这边新建一个名为SerialPort的工程

5.1 修改.Pro文件

  使用串口,需要在.pro项目文件中添加serialport串口模块的支持

QT       += core gui serialport

在这里插入图片描述

5.2 修改mainwindow.h头文件

  头文件需要包含串口常用的两个类QSerialPortInfoQSerialPort

#include <QSerialPort>
#include <QSerialPortInfo>
  • QSerialPortInfo:提供有关现有串行端口的信息
  • QSerialPort:提供访问串行端口的功能
#ifndef MAINWINDOW_H
#define MAINWINDOW_H

#include <QMainWindow>
#include <QSerialPort>
#include <QSerialPortInfo>
#include <QPushButton>
#include <QTextBrowser>
#include <QTextEdit>
#include <QVBoxLayout>
#include <QLabel>
#include <QComboBox>
#include <QGridLayout>
#include <QMessageBox>
#include <QDebug>

QT_BEGIN_NAMESPACE
namespace Ui {
class MainWindow;
}
QT_END_NAMESPACE

class MainWindow : public QMainWindow
{
    Q_OBJECT

public:
    MainWindow(QWidget *parent = nullptr);
    ~MainWindow();

private:
    /* 串口对象 */
    QSerialPort *serialPort;

    /* 用作接收数据 */
    QTextBrowser *textBrowser;

    /* 用作发送数据 */
    QTextEdit *textEdit;

    /* 按钮 */
    QPushButton *pushButton[2];

    /* 下拉选择盒子 */
    QComboBox *comboBox[5];

    /* 标签 */
    QLabel *label[5];

    /* 垂直布局 */
    QVBoxLayout *vboxLayout;

    /* 网络布局 */
    QGridLayout *gridLayout;

    /* 主布局 */
    QWidget *mainWidget;

    /* 设置功能区域 */
    QWidget *funcWidget;

    /* 布局初始化 */
    void layoutInit();

    /* 扫描系统可用串口 */
    void scanSerialPort();

    /* 波特率项初始化 */
    void baudRateItemInit();

    /* 数据位项初始化 */
    void dataBitsItemInit();

    /* 检验位项初始化 */
    void parityItemInit();

    /* 停止位项初始化 */
    void stopBitsItemInit();

private slots:
    void sendPushButtonClicked();
    void openSerialPortPushButtonClicked();
    void serialPortReadyRead();
};
#endif // MAINWINDOW_H

5.3 修改mainwindow.cpp源文件

  QSerialPortInfo使用静态函数生成 QSerialPortInfo 对象的列表。列表中的每个 QSerialPortInfo 对象代表一个串行端口,可以查询该端口的名称,系统位置,描述和制造商。QSerialPortInfo类也可以被用作setPort()方法的输入参数,这些参数限定串口端口号,波特率等。

  对于QSerialPort类,我们可以使用如下方法来设置串口的相关参数。

  • setBaudRate()设置波特率
  • setDataBits()设置数据位
  • setParity()设置校验位
  • setStopBits()设置停止位
  • setFlowControl()设置流控制

  设置端口后,可以使用open()方法以只读 (r/o)、仅写 (w/o) 或可读可写 (r/w) 模式打开它。成功打开后,可以使用close()方法关闭端口并取消 I/O 操作。一旦知道端口已准备好读取或写入,就可以使用read()write()方法。

#include "mainwindow.h"
#include <QGuiApplication>
#include <QScreen>
#include <QRect>

MainWindow::MainWindow(QWidget *parent)
    : QMainWindow(parent)
{
    /* 布局初始化 */
    layoutInit();

    /* 扫描系统的串口 */
    scanSerialPort();

    /* 波特率项初始化 */
    baudRateItemInit();

    /* 数据位项初始化 */
    dataBitsItemInit();

    /* 检验位项初始化 */
    parityItemInit();

    /* 停止位项初始化 */
    stopBitsItemInit();
}


void MainWindow::layoutInit()
{
    /* 获取屏幕的分辨率,Qt官方建议使用这
     * 种方法获取屏幕分辨率,防上多屏设备导致对应不上
     * 注意,这是获取整个桌面系统的分辨率
     */
    QList <QScreen *> list_screen =  QGuiApplication::screens();

    /* 如果是ARM平台,
直接设置大小为屏幕的大小 */
#if __arm__
    /* 重设大小 */
    this->resize(list_screen.at(0)->geometry().width(),
                 list_screen.at(0)->geometry().height());
#else
    /* 否则则设置主窗体大小为800x480 */
    this->resize(800, 480);
#endif
    /* 初始化 */
    serialPort = new QSerialPort(this);
    textBrowser = new QTextBrowser();
    textEdit = new QTextEdit();
    vboxLayout = new QVBoxLayout();
    funcWidget = new QWidget();
    mainWidget = new QWidget();
    gridLayout = new QGridLayout();

    /* QList链表,字符串类型 */
    QList <QString> list1;
    list1<<"串口号:"<<"波特率:"<<"数据位:"<<"检验位:"<<"停止位:";

    for (int i = 0; i < 5; i++) {
        label[i] = new QLabel(list1[i]);
        /* 设置最小宽度与高度 */
        label[i]->setMinimumSize(80, 30);
        /* 自动调整label的大小 */
        label[i]->setSizePolicy(
            QSizePolicy::Expanding,
            QSizePolicy::Expanding
            );
        /* 将label[i]添加至网格的坐标(0, i) */
        gridLayout->addWidget(label[i], 0, i);
    }

    for (int i = 0; i < 5; i++) {
        comboBox[i] = new QComboBox();
        comboBox[i]->setMinimumSize(80, 30);
        /* 自动调整label的大小 */
        comboBox[i]->setSizePolicy(
            QSizePolicy::Expanding,
            QSizePolicy::Expanding
            );
        /* 将comboBox[i]添加至网格的坐标(1, i) */
        gridLayout->addWidget(comboBox[i], 1, i);
    }

    /* QList链表,字符串类型 */
    QList <QString> list2;
    list2<<"发送"<<"打开串口";

    for (int i = 0; i < 2; i++) {
        pushButton[i] = new QPushButton(list2[i]);
        pushButton[i]->setMinimumSize(80, 30);
        /* 自动调整label的大小 */
        pushButton[i]->setSizePolicy(
            QSizePolicy::Expanding,
            QSizePolicy::Expanding
            );
        /* 将pushButton[0]添加至网格的坐标(i, 5) */
        gridLayout->addWidget(pushButton[i], i, 5);
    }
    pushButton[0]->setEnabled(false);

    /* 布局 */
    vboxLayout->addWidget(textBrowser);
    vboxLayout->addWidget(textEdit);
    funcWidget->setLayout(gridLayout);
    vboxLayout->addWidget(funcWidget);
    mainWidget->setLayout(vboxLayout);
    this->setCentralWidget(mainWidget);

    /* 占位文本 */
    textBrowser->setPlaceholderText("接收到的消息");
    textEdit->setText("myQt");

    /* 信号槽连接 */
    connect(pushButton[0], SIGNAL(clicked()),
            this, SLOT(sendPushButtonClicked()));
    connect(pushButton[1], SIGNAL(clicked()),
            this, SLOT(openSerialPortPushButtonClicked()));

    connect(serialPort, SIGNAL(readyRead()),
            this, SLOT(serialPortReadyRead()));
}

void MainWindow::scanSerialPort()
{
    /* 查找可用串口 */
    foreach (const QSerialPortInfo &info,
             QSerialPortInfo::availablePorts()) {
        comboBox[0]->addItem(info.portName());
    }
}

void MainWindow::baudRateItemInit()
{
    /* QList链表,字符串类型 */
    QList <QString> list;
    list<<"1200"<<"2400"<<"4800"<<"9600"
         <<"19200"<<"38400"<<"57600"
         <<"115200"<<"230400"<<"460800"
         <<"921600";
    for (int i = 0; i < 11; i++) {
        comboBox[1]->addItem(list[i]);
    }
    comboBox[1]->setCurrentIndex(7);
}

void MainWindow::dataBitsItemInit()
{
    /* QList链表,字符串类型 */
    QList <QString> list;
    list<<"5"<<"6"<<"7"<<"8";
    for (int i = 0; i < 4; i++) {
        comboBox[2]->addItem(list[i]);
    }
    comboBox[2]->setCurrentIndex(3);
}

void MainWindow::parityItemInit()
{
    /* QList链表,字符串类型 */
    QList <QString> list;
    list<<"None"<<"Even"<<"Odd"<<"Space"<<"Mark";
    for (int i = 0; i < 5; i++) {
        comboBox[3]->addItem(list[i]);
    }
    comboBox[3]->setCurrentIndex(0);
}

void MainWindow::stopBitsItemInit()
{
    /* QList链表,字符串类型 */
    QList <QString> list;
    list<<"1"<<"2";
    for (int i = 0; i < 2; i++) {
        comboBox[4]->addItem(list[i]);
    }
    comboBox[4]->setCurrentIndex(0);
}

void MainWindow::sendPushButtonClicked()
{
    /* 获取textEdit数据,转换成utf8格式的字节流 */
    QByteArray data = textEdit->toPlainText().toUtf8();
    serialPort->write(data);
}

void MainWindow::openSerialPortPushButtonClicked()
{
    if (pushButton[1]->text() == "打开串口") {
        /* 设置串口名 */
        serialPort->setPortName(comboBox[0]->currentText());
        /* 设置波特率 */
        serialPort->setBaudRate(comboBox[1]->currentText().toInt());
        /* 设置数据位数 */
        switch (comboBox[2]->currentText().toInt()) {
        case 5:
            serialPort->setDataBits(QSerialPort::Data5);
            break;
        case 6:
            serialPort->setDataBits(QSerialPort::Data6);
            break;
        case 7:
            serialPort->setDataBits(QSerialPort::Data7);
            break;
        case 8:
            serialPort->setDataBits(QSerialPort::Data8);
            break;
        default: break;
        }
        /* 设置奇偶校验 */
        switch (comboBox[3]->currentIndex()) {
        case 0:
            serialPort->setParity(QSerialPort::NoParity);
            break;
        case 1:
            serialPort->setParity(QSerialPort::EvenParity);
            break;
        case 2:
            serialPort->setParity(QSerialPort::OddParity);
            break;
        case 3:
            serialPort->setParity(QSerialPort::SpaceParity);
            break;
        case 4:
            serialPort->setParity(QSerialPort::MarkParity);
            break;
        default: break;
        }
        /* 设置停止位 */
        switch (comboBox[4]->currentText().toInt()) {
        case 1:
            serialPort->setStopBits(QSerialPort::OneStop);
            break;
        case 2:
            serialPort->setStopBits(QSerialPort::TwoStop);
            break;
        default: break;
        }
        /* 设置流控制 */
        serialPort->setFlowControl(QSerialPort::NoFlowControl);
        if (!serialPort->open(QIODevice::ReadWrite))
            QMessageBox::about(NULL, "错误",
                               "串口无法打开!可能串口已经被占用!");
        else {
            for (int i = 0; i < 5; i++)
                comboBox[i]->setEnabled(false);
            pushButton[1]->setText("关闭串口");
            pushButton[0]->setEnabled(true);
        }
    } else {
        serialPort->close();
        for (int i = 0; i < 5; i++)
            comboBox[i]->setEnabled(true);
        pushButton[1]->setText("打开串口");
        pushButton[0]->setEnabled(false);
    }
}

void MainWindow::serialPortReadyRead()
{
    /* 接收缓冲区中读取数据 */
    QByteArray buf = serialPort->readAll();
    textBrowser->insertPlainText(QString(buf));
}

MainWindow::~MainWindow()
{
}
  • layoutInit()界面布局初始化设置,根据实际的屏的大小,设置全屏显示。其中我们用到垂直布局和网格布局
  • scanSerialPort()查找系统可用的串口,并添加串口名到 comboBox[0]中。
  • baudRateItemInit()波特率初始化,预设常用的波特率,115200 作为默认选项。并添加波特率到comboBox[1]中。
  • dataBitsItemInit()数据位项初始化,设置默认数据位为 8。
  • parityItemInit()校验位项初始化,默认无校验位。
  • stopBitsItemInit()停止位项初始化,默认停止位为 1。
  • sendPushButtonClicked()发送数据,点击发送按钮时触发。
  • openSerialPortPushButtonClicked()打开或者关闭串口。以我们设置的项使用 Qt 串口提供的设置串口的方法如 setDataBits(QSerialPort::DataBits)等,按步骤设置完串口需要配置的参数就可以打开或者关闭串口了。
  • serialPortReadyRead()从缓冲区里读出数据,并显示到 textBrowser 里。

5.4 效果

在这里插入图片描述

六、QT程序发布与打包

6.1 添加图标

  找一个.ico文件,图标下载网址如:https://www.iconfont.cn/
在这里插入图片描述
  然后在.pro文件中添加如下一行代码:

RC_ICONS = SerialPort.ico

在这里插入图片描述

6.2 生成Release版程序

  如果要发布程序需要切换为Release版本(Debug为调试版本),编译器会对生成的Release版可执行程序进行优化,生成的可执行程序会更小。
在这里插入图片描述
  在Release里找到SerialPort.exe,双击发现打不开,报错原因是找不到一些相关的动态库
在这里插入图片描述
在这里插入图片描述

6.3 添加动态库

  Qt官方给我们提供了相关的发布工具,这个工具叫做windeployqt.exe,文件目录在安装路径的bin文件夹里,如我这边是C:\Qt\5.15.0\mingw81_32\bin
在这里插入图片描述
  先新建一个文件夹,将SerialPort.exe文件复制进来。如果安装时配好环境变量,可以直接打开CMD或者shell,这边我们选择Powershell
在这里插入图片描述
  在当前目录下执行以下命令进行打包

windeployqt SerialPort.exe

在这里插入图片描述
  此时再双击SerialPort.exe就可以运行
在这里插入图片描述
注意:环境变量里bin路径配置要与新建Qt工程选择的编译器版本相同,否则无法运行。如一个是64位一个为32位

6.4 Qt程序打包

6.4.1 打包成单文件版

  上面的绿色便携版的不便之处是,发送给别人的时候还需要先压缩一下,别人接受后还需要先解压再使用,就很不方便。因此单文件版就应运而生,给别人发送的是一个包含运行环境的exe文件,双击即可使用。
  使用Enigma Virtual Box,官网:https://www.enigmaprotector.com/en/downloads.html
  先选择要打包的文件
在这里插入图片描述
  新建递归文件夹,然后把上一小节整个文件夹拖进来
在这里插入图片描述
  然后开始压缩文件
在这里插入图片描述
  然后就可以生成一个可以运行的文件SerialPort_boxed.exe
在这里插入图片描述

6.4.2 打包成可安装版本

  将应用程序和相关的动态库打包成安装包的工具有很多,拿Inno Setup使用举例,官网:https://jrsoftware.org/isdl.php#stable

  新建直接Next
在这里插入图片描述
  填写相关信息
在这里插入图片描述
  设置安装文件夹
在这里插入图片描述

  添加应用程序与依赖文件夹
在这里插入图片描述
  Next到这里,是应用程序文档信息,一般空着就行。
在这里插入图片描述
  继续到选择安装语言,这里可以去inno setup官网找到translations,点击然后下拉找到简体中文语言包Chinese (Simplified)下载下来。然后找到Inno Setup安装文件,进入Languages子文件夹,将语言包复制进去就行。
在这里插入图片描述
  设置安装包信息
在这里插入图片描述
  继续到执行脚本
在这里插入图片描述
  双击生成文件可以安装
在这里插入图片描述

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1700454.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

【Python】 Python函数返回多个值的多种方法

基本原理 在Python中&#xff0c;函数通常用于封装一段代码&#xff0c;使其可以重复调用。有时&#xff0c;我们希望一个函数能够返回多个值&#xff0c;Python提供了几种不同的方法来实现这一点。 代码示例 示例1&#xff1a;使用元组返回多个值 Python中&#xff0c;元组…

TYPE-C接口桌面显示器:办公与娱乐新玩法

随着科技的不断进步&#xff0c;传统桌面显示器已经难以满足现代人对高效办公与极致娱乐体验的追求。在这个背景下&#xff0c;新型的TYPE-C接口桌面显示器应运而生&#xff0c;以其独特的功能和设计&#xff0c;引领了未来办公与娱乐的新潮流。 添加图片注释&#xff0c;不超过…

Linux 批量网络远程PXE

一、搭建PXE远程安装服务器 1、yum -y install tftp-server xinetd #安装tftp服务 2、修改vim /etc/xinetd.d/tftpTFTP服务的配置文件 systemctl start tftp systemctl start xinetd 3、yum -y install dhcp #---安装服务 cp /usr/share/doc/dhc…

云上聚智共创未来 | 移动云的项目实战,10分钟让你获得高度可玩的个人博客网站

&#x1f3ac; 鸽芷咕&#xff1a;个人主页 &#x1f525; 个人专栏: 《C干货基地》《粉丝福利》 ⛺️生活的理想&#xff0c;就是为了理想的生活! 引入 随着互联网的发展各种以前看起来离我们比较遥远的词越来越近了&#xff0c;比如 云服务、大数据、区块链、容器这些听起来…

免费且非常火的日程管理软件:飞项

一、简介 1、在日常繁忙的工签中&#xff0c;是否事情一大堆却记不住&#xff1f;系统自带的日历用着却是不方便&#xff0c;不顺手&#xff0c;提醒不及时&#xff1f;待办、打卡、记事乱七八糟的混在一起&#xff0c;关键时候找不到&#xff1f;市面上的日程管理软件那么多&a…

用go语言实现一个有界协程池

写在文章开头 本篇文章算是对go语言系列的一个收尾&#xff0c;通过go语言实现一个实现一个简单的有界协程池。 Hi&#xff0c;我是 sharkChili &#xff0c;是个不断在硬核技术上作死的 java coder &#xff0c;是 CSDN的博客专家 &#xff0c;也是开源项目 Java Guide 的维护…

【C语言】自定义类型:联合与枚举的简明概述

&#x1f525;引言 关于自定义类型除了我们常用的结构体&#xff0c;还有联合与枚举也是属于自定义类型。本篇将简单介绍联合与枚举基本概念和使用方法 &#x1f308;个人主页&#xff1a;是店小二呀 &#x1f308;C语言笔记专栏&#xff1a;C语言笔记 &#x1f308;C笔记专栏&…

中国改革报是什么级别的报刊?在哪些领域具有较高的影响力?

中国改革报是什么级别的报刊&#xff1f;在哪些领域具有较高的影响力&#xff1f; 《中国改革报》是国家发展和改革委员会主管的全国性综合类报纸。它在经济领域和改革发展方面具有重要的影响力&#xff0c;是传递国家政策、反映改革动态的重要平台。该报对于推动中国的经济改…

【Java限流算法详解及实现】

Java限流算法详解及实现 在高并发场景下&#xff0c;限流是保护系统的重要手段。限流算法可以帮助我们在流量过大时进行合理的控制&#xff0c;避免系统崩溃。本文将详细介绍几种常见的限流算法及其在Java中的实现。 Java限流算法详解及实现 Java限流算法详解及实现一、令牌桶…

Android 深入系统源码探讨 Activity、Window 和 View 的关系与实践

文章目录 1、概括2、Android Window 设计2.1、Window 类2.2、PhoneWindow2.3、WindowManager2.4、ViewRootImpl2.5、DecorView 3、Android Activity 设计3.1、Activity的基本概念3.2.、Activity的生命周期3.3、Activity的内部结构 4、Android View 设计4.1、View的基本概念4.2、…

构建智慧城市公共服务系统的功能架构设计

随着城市化进程的加速&#xff0c;城市公共服务系统在保障居民生活品质、提升城市管理水平方面扮演着愈发重要的角色。构建智慧城市公共服务系统的功能架构设计至关重要&#xff0c;它不仅需要充分考虑居民需求与城市管理的实际情况&#xff0c;还需要整合先进的科技手段&#…

vue3快速入门(局部使用)

目录 前置知识JavaScript-导入导出 入门操作 变量渲染页面 局部使用vue的实现步骤 vue指令 v-for v-bind v-if v-show v-on v-model 生命周期 前置知识JavaScript-导入导出 正常情况在html导入js文件是全部导入&#xff0c;这样会导致性能上的损失 。 JS提供的…

Docker之xfs文件系统下安装报错解决方案

一、需求说明 centos系统下安装docker最新版的时候&#xff0c;安装成功&#xff0c;启动的时候报错。报错信息“failed to start daemon: error initializing graphdriver: overlay2: the backing xfs filesystem is formatted without d_type support, which leads to incorr…

5.26机器人基础-DH参数 正解

1.建立DH坐标系 1.确定Zi轴&#xff08;关节轴&#xff09; 2.确定基础坐标系 3.确定Xi方向&#xff08;垂直于zi和zi1的平面&#xff09; 4.完全确定各个坐标系 例子&#xff1a; 坐标系的布局是由个人决定的&#xff0c;可以有不同的选择 标准坐标系布局&#xff1a; …

NDIS协议驱动(一)

Microsoft Windows 操作系统使用基于 1978 年国际标准化组织 (ISO) 开发的七层网络模型的网络体系结构。 ISO 开放系统互连 (OSI) 参考模型将网络描述为“一系列协议层&#xff0c;具有分配给每个层的一组特定函数。 每个层都向更高层提供特定的服务&#xff0c;同时阻止这些层…

vscode:如何解决”检测到include错误,请更新includePath“

vscode:如何解决”检测到include错误&#xff0c;请更新includePath“ 前言解决办法1 获取includePath路径2 将includePath路径添加到指定文件3 保存 前言 配置vscode是出现如下错误&#xff1a; 解决办法 1 获取includePath路径 通过cmd打开终端&#xff0c;输入如下指令&a…

有个小伙把 MyBatis 替换成 MyBatis-Plus,上线后就被开了!!

MyBatis-Plus 替换 MyBatis 首先&#xff0c;我们准备了一张名为 tbl_order 的表&#xff0c;并初始化了其中的两条数据。 DROP TABLE IF EXISTS tbl_order; CREATE TABLE tbl_order (id bigint(0) UNSIGNED NOT NULL AUTO_INCREMENT COMMENT 自增主键,order_no varchar(50)…

云易办springboot+vue后端

springbootvue云易办后端项目完成 一.创建项目 创建父项目&#xff1a;yeb&#xff0c; 使用spring Initializr&#xff0c;完成创建之后删除无用文件夹&#xff0c;作为父项目 添加packaging <packaging>pom</packaging>二.创建子模块&#xff1a;yeb-server …

这或许是国产游戏出海的最佳时机

《刺客信条&#xff1a;影》过于政治正确的选角激怒了全球玩家&#xff0c;而社交媒体上有玩家讨论育碧是否应该因为刻意加入DEI&#xff08;多元化&#xff09;而延期《刺客信条&#xff1a;影》时&#xff0c;没想到这得到了X拥有人埃隆马斯克的回复。马斯克表示“DEI&#x…

内网穿透实现公网访问自己搭建的Ollma架构的AI服务器

内网穿透实现公网访问自己搭建的Ollma架构的AI服务器 [2024年5月9号我发布一个博文关于搭建本地AI服务器的博文][https://blog.csdn.net/weixin_41905135/article/details/138588043?spm1001.2014.3001.5501]&#xff0c;今天我们内网穿透实现从公网访问我的本地AI服务器&…