Qt 學習筆記全系列傳送門:
1、建立專案
實現串列埠助手
-
建立 Qt Widgets Application 專案 seial
-
基類選擇 Widget
2、UI
-
UI設計
- 接收框元件,在分類 Input Widgets 中,Plain Text Edit 元件(QPlainTextEdit),雙擊可以編輯選項,置頂項為預設選擇屬性,勾選元件的只讀屬性 readOnly
- 屬性選擇,在分類 Input Widgets 中,Combo Box 元件(QComboBox)
- 傳送框,在分類在 Input Widgets 中,Line Edit 元件(QLineEdit)
- 資訊框,寫個廣告之類的可以使用,在分類 中,Group Box 元件(QGroupBox)
- 控制元件改名
-
UI程式碼展示
<?xml version="1.0" encoding="UTF-8"?> <ui version="4.0"> <class>Widget</class> <widget class="QWidget" name="Widget"> <property name="geometry"> <rect> <x>0</x> <y>0</y> <width>800</width> <height>480</height> </rect> </property> <property name="windowTitle"> <string>Widget</string> </property> <widget class="QWidget" name="layoutWidget"> <property name="geometry"> <rect> <x>31</x> <y>31</y> <width>737</width> <height>385</height> </rect> </property> <layout class="QGridLayout" name="gridLayout_3"> <item row="0" column="0"> <widget class="QPlainTextEdit" name="recvEdit"> <property name="readOnly"> <bool>true</bool> </property> </widget> </item> <item row="1" column="0"> <spacer name="verticalSpacer"> <property name="orientation"> <enum>Qt::Vertical</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>20</width> <height>40</height> </size> </property> </spacer> </item> <item row="2" column="0"> <layout class="QGridLayout" name="gridLayout_2"> <item row="0" column="0"> <layout class="QGridLayout" name="gridLayout"> <item row="0" column="0"> <widget class="QLabel" name="label_2"> <property name="text"> <string>波特率</string> </property> </widget> </item> <item row="0" column="1"> <widget class="QComboBox" name="baundrateCb"> <item> <property name="text"> <string>4800</string> </property> </item> <item> <property name="text"> <string>9600</string> </property> </item> <item> <property name="text"> <string>115200</string> </property> </item> </widget> </item> <item row="1" column="0"> <widget class="QLabel" name="label"> <property name="text"> <string>串列埠號</string> </property> </widget> </item> <item row="1" column="1"> <widget class="QComboBox" name="serialCb"/> </item> <item row="2" column="0"> <widget class="QLabel" name="label_5"> <property name="text"> <string>資料位</string> </property> </widget> </item> <item row="2" column="1"> <widget class="QComboBox" name="dataCb"> <item> <property name="text"> <string>5</string> </property> </item> <item> <property name="text"> <string>6</string> </property> </item> <item> <property name="text"> <string>7</string> </property> </item> <item> <property name="text"> <string>8</string> </property> </item> </widget> </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="stopCb"> <item> <property name="text"> <string>1</string> </property> </item> <item> <property name="text"> <string>1.5</string> </property> </item> <item> <property name="text"> <string>2</string> </property> </item> </widget> </item> <item row="4" column="0"> <widget class="QLabel" name="label_3"> <property name="text"> <string>校驗位</string> </property> </widget> </item> <item row="4" column="1"> <widget class="QComboBox" name="checkCb"> <item> <property name="text"> <string>none</string> </property> </item> </widget> </item> </layout> </item> <item row="0" column="1"> <spacer name="horizontalSpacer_4"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item row="0" column="2"> <layout class="QVBoxLayout" name="verticalLayout_2"> <item> <widget class="QGroupBox" name="groupBox"> <property name="title"> <string>歡迎使用,這是一個資訊框</string> </property> <widget class="QLabel" name="label_6"> <property name="geometry"> <rect> <x>120</x> <y>30</y> <width>161</width> <height>21</height> </rect> </property> <property name="text"> <string>demo info...</string> </property> </widget> </widget> </item> <item> <widget class="QLineEdit" name="sendEdit"/> </item> <item> <layout class="QHBoxLayout" name="horizontalLayout_6"> <item> <widget class="QPushButton" name="openBt"> <property name="text"> <string>開啟串列埠</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="closeBt"> <property name="text"> <string>關閉串列埠</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer_2"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="sendBt"> <property name="text"> <string>傳送</string> </property> </widget> </item> <item> <spacer name="horizontalSpacer_3"> <property name="orientation"> <enum>Qt::Horizontal</enum> </property> <property name="sizeHint" stdset="0"> <size> <width>40</width> <height>20</height> </size> </property> </spacer> </item> <item> <widget class="QPushButton" name="clearBt"> <property name="text"> <string>清空</string> </property> </widget> </item> </layout> </item> </layout> </item> </layout> </item> </layout> </widget> </widget> <layoutdefault spacing="6" margin="11"/> <resources/> <connections/> </ui>
3、邏輯功能
-
在工程檔案中引入
serialport
QT += core gui serialport
-
獲取串列埠資訊並展示到頁面上,在目前 UI 對應的 cpp 的構造中進行
說明:需要連線微控制器才能顯示串列埠號
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); QStringList serialNamePorts; // QSerialPort 是串列埠資訊類,用於存放串列埠資訊 // QSerialPortInfo::availablePorts() 自動搜尋可用串列埠,返回串列埠資訊類物件的陣列 foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) { // 將得到的串列埠資訊的串列埠號加入到 QStringList 中 serialNamePorts<<info.portName(); } // 將可用串列埠的列表顯示到頁面的下拉框中 ui->serialCb->addItems(serialNamePorts); }
-
其他控制元件的邏輯功能
-
點選開啟串列埠時對串列埠進行初始化
-
對串列埠的宣告和建立
-
標頭檔案
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QSerialPort> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT public: explicit Widget(QWidget *parent = 0); ~Widget(); // 宣告QSerialPort *serialPort QSerialPort *serialPort; private slots: void on_openBt_clicked(); void on_closeBt_clicked(); void on_sendBt_clicked(); void on_clearBt_clicked(); private: Ui::Widget *ui; }; #endif // WIDGET_H
-
Cpp檔案
#include "widget.h" #include "ui_widget.h" #include <QSerialPortInfo> #include <QMessageBox> Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); // ... serialPort = new QSerialPort(this); // ... } Widget::~Widget() { delete serialPort; delete ui; }
-
-
開啟按鈕單擊訊號的槽函式
// 點選開啟串列埠時將資料設定進串列埠並開啟串列埠 void Widget::on_openBt_clicked() { QSerialPort::BaudRate baudReat; QSerialPort::DataBits dataBits; QSerialPort::StopBits stopBits; QSerialPort::Parity checkBits; // 獲取介面上的值 switch(ui->baundrateCb->currentText().toInt()) { case QSerialPort::Baud4800: baudReat = QSerialPort::Baud4800; break; case QSerialPort::Baud9600: baudReat = QSerialPort::Baud9600; break; case QSerialPort::Baud115200: baudReat = QSerialPort::Baud115200; break; } switch(ui->dataCb->currentText().toInt()) { case QSerialPort::Data5: dataBits = QSerialPort::Data5; break; case QSerialPort::Data6: dataBits = QSerialPort::Data6; break; case QSerialPort::Data7: dataBits = QSerialPort::Data7; break; case QSerialPort::Data8: dataBits = QSerialPort::Data8; break; } int stopTmp = ui->stopCb->currentText().toInt(); if (stopTmp == QSerialPort::OneStop) { stopBits = QSerialPort::OneStop; } else if (stopTmp == QSerialPort::OneAndHalfStop) { stopBits = QSerialPort::OneAndHalfStop; } else if (stopTmp == QSerialPort::TwoStop) { stopBits = QSerialPort::TwoStop; } if (ui->checkCb->currentText() == "none") { checkBits = QSerialPort::NoParity; } // 使用獲取到的資料設定串列埠 serialPort->setPortName(ui->serialCb->currentText()); serialPort->setBaudRate(baudReat); serialPort->setDataBits(dataBits); serialPort->setStopBits(stopBits); serialPort->setParity(checkBits); // 開啟串列埠,需要先判斷串列埠是否開啟成功 if (serialPort->open(QIODevice::ReadWrite) == true) { QMessageBox::information(this, "提示", "success!"); } else { QMessageBox::critical(this, "提示", "failed!"); } }
-
關閉按鈕單擊訊號槽函式
void Widget::on_closeBt_clicked() { serialPort->close(); }
-
傳送按鈕單擊訊號槽函式
void Widget::on_sendBt_clicked() { // 將UI傳送的QString轉換為char* 型別,寫入到serialPort serialPort->write(ui->sendEdit->text().toLocal8Bit().data()); }
-
串列埠有東西可讀時,在接收框中進行展示
-
定義槽函式,在標頭檔案中
#ifndef WIDGET_H #define WIDGET_H #include <QWidget> #include <QSerialPort> namespace Ui { class Widget; } class Widget : public QWidget { Q_OBJECT // ... private slots: // ... // 定義串列埠有東西可讀時觸發的槽函式 void serialPortReadyRead_Slot(); // ... }; #endif // WIDGET_H
-
手動繫結可讀訊號與槽函式,在構造中
Widget::Widget(QWidget *parent) : QWidget(parent), ui(new Ui::Widget) { ui->setupUi(this); QStringList serialNamePorts; serialPort = new QSerialPort(this); // 手動關聯讀訊號與自定義槽函式serialPortReadyRead_Slot(),串列埠有東西可讀時觸發槽函式 connect(serialPort, SIGNAL(readyRead()), this, SLOT(serialPortReadyRead_Slot())); // ... }
-
實現槽函式
// 串列埠有東西可讀時產生訊號,觸發槽函式 void Widget::serialPortReadyRead_Slot() { // 接收UI中輸入框的資料 QString buffer = QString(serialPort->readAll()); // 將接收到的資料顯示到UI的recvEdit中 ui->recvEdit->appendPlainText(buffer); }
-
-
清除按鈕單擊訊號槽函式
void Widget::on_clearBt_clicked() { ui->recvEdit->clear(); }
-
-
4、程式打包和部署
-
切換到 Release 模式進行編譯
由於缺少動態庫,打包好的程式暫時還無法執行
-
匯出檔案位置:位於專案目錄所在路徑下,檔名以 Release 結尾,如:
build-seial-Desktop_Qt_5_11_1_MinGW_32bit-Release
-
圖示:
-
-
為打包好的程式更換圖示
需要使用
.ico
格式的圖片-
將圖示複製到工程目錄下
-
在工程檔案中新增如下程式碼,再重新編譯即可
RC_ICONS = serial_icon.ico
-
-
封包操作,需要用到 Qt 的控制檯
-
建立一個新的目錄,用於存放封包好的檔案,不能包含中文路徑
-
將打包好的
.exe
檔案複製到新的目錄下 -
從控制檯進入新目錄中
cd /d C:\xxx\xxx
D:\Tools\Qt\Qt5.11.1\5.11.1\mingw53_32>cd /d C:\Users\Dandelion\Desktop\SerialTools C:\Users\Dandelion\Desktop\SerialTools>dir 驅動器 C 中的卷是 OS 卷的序列號是 EAE6-1E0A C:\Users\Dandelion\Desktop\SerialTools 的目錄 2023/03/10 02:22 <DIR> . 2023/03/10 02:20 <DIR> .. 2023/03/10 02:17 48,640 seial.exe 1 個檔案 48,640 位元組 2 個目錄 63,272,501,248 可用位元組 C:\Users\Dandelion\Desktop\SerialTools>
-
使用
windeployqt
工具將動態庫加到當前目錄下:windeployqt seial.exe
C:\Users\Dandelion\Desktop\SerialTools>windeployqt seial.exe C:\Users\Dandelion\Desktop\SerialTools\seial.exe 32 bit, release executable Adding Qt5Svg for qsvgicon.dll Skipping plugin qtvirtualkeyboardplugin.dll due to disabled dependencies (Qt5Qml Qt5Quick). Direct dependencies: Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets All dependencies : Qt5Core Qt5Gui Qt5SerialPort Qt5Widgets To be deployed : Qt5Core Qt5Gui Qt5SerialPort Qt5Svg Qt5Widgets Updating Qt5Core.dll. Updating Qt5Gui.dll. Updating Qt5SerialPort.dll. Updating Qt5Svg.dll. Updating Qt5Widgets.dll. Updating libGLESV2.dll. Updating libEGL.dll. Updating D3Dcompiler_47.dll. Updating opengl32sw.dll. Updating libgcc_s_dw2-1.dll. Updating libstdc++-6.dll. Updating libwinpthread-1.dll. Patching Qt5Core.dll... Creating directory C:/Users/Dandelion/Desktop/SerialTools/iconengines. Updating qsvgicon.dll. Creating directory C:/Users/Dandelion/Desktop/SerialTools/imageformats. Updating qgif.dll. Updating qicns.dll. Updating qico.dll. Updating qjpeg.dll. Updating qsvg.dll. Updating qtga.dll. Updating qtiff.dll. Updating qwbmp.dll. Updating qwebp.dll. Creating directory C:/Users/Dandelion/Desktop/SerialTools/platforms. Updating qwindows.dll. Creating directory C:/Users/Dandelion/Desktop/SerialTools/styles. Updating qwindowsvistastyle.dll. Creating C:\Users\Dandelion\Desktop\SerialTools\translations... Creating qt_ar.qm... Creating qt_bg.qm... Creating qt_ca.qm... Creating qt_cs.qm... Creating qt_da.qm... Creating qt_de.qm... Creating qt_en.qm... Creating qt_es.qm... Creating qt_fi.qm... Creating qt_fr.qm... Creating qt_gd.qm... Creating qt_he.qm... Creating qt_hu.qm... Creating qt_it.qm... Creating qt_ja.qm... Creating qt_ko.qm... Creating qt_lv.qm... Creating qt_pl.qm... Creating qt_ru.qm... Creating qt_sk.qm... Creating qt_uk.qm... C:\Users\Dandelion\Desktop\SerialTools>
-