項目總結-上位機


前幾天受朋友之托,給他們的項目寫個上位機。有些經驗分享給大家

要求是上位機收到通過串口發送的數據,根據數據顯示空車位的數量。

    *最終上位機擁有的值得一談的功能:

  1. 串口通信的相關設置
  2. 數據保存
  3. 界面隨窗口縮放的實現
  4. 軟件打包
  5. 。。。然后就沒有了

1.開始寫軟件之前首先明確目的,軟件應該實行什么功能,然后設計界面,最后才開始寫代碼。

    界面設計(Visio設計,當然其他工具也可以):

2.軟件結構設計

整個軟件只有一個窗口tabwidget,在其中嵌入三個繼承自Qwidgetd的類,一個用於串口通信相關設置,一個用於顯示車位數,一個是幫助頁面。

 

3.軟件頁面的設計與實現

    之前看過其他人寫的上位機,有的界面做得不是很爽,主要是界面固定,不能進行窗口縮放。

    說一下如何讓軟件的界面能夠大小根據口的大小縮放?窗

  1. 首先要知道,軟件界面的自動縮放,可以由窗口控制。就是說設置好界面后把控制權交給QT的程序框架就行了,框架會進行調整。值得一提的是,個人感覺qt設計師不好用,當界面的控件多的時候,布局起來往往不如人意,特別是要實現窗口縮放的功能,很麻煩。推薦用代碼布局,可操作性強,配置起來也簡單明了。如果是小項目,界面簡單,那就無所謂了。
  2. 把所有的布局最終嵌入到一個布局里面,然后設置這個布局為窗口的布局,剩下的縮放就交給qt控件了。

     

4.串口通信的實現

    qt5提供了串口類,所以我們只需要調用修改函數進行配置就能夠實現通信了。qt5的示例程序里面有查看程序,輸入"serial"就可以檢索出來。

    對串口的操作類似文件操作。過程就是:打開串口—>使用串口—>關閉串口。完整的過程:檢索串口—>打開串口—>配置波特率、停止位等等—>對串口讀寫—>不使用時關閉。

5.代碼有些是有注釋,有些是沒有注釋的,還有一些是自注釋(通過函數名稱就知道是干啥的)。

    

6.一些需要注意的問題

    1.要想使用串口類需要在工程文件添加serialport

        eg. QT += core gui serialport

    2.為軟件的使用方便性,可以設置"伙伴"(setBuddy)

    3.注意控件的寬度,有時候界面縮放效果不理想,並不是布局不好,而是控件的一些屬性(高度、寬度)影響了布局。

7.這個程序車位顯示模塊做得真菜,判斷有無車位居然使用的是if()else()……..

    他們做的下位機連個通信協議都定。我這邊也是沒辦法,把老師忽悠過關就行了。反正不是我的項目,O(∩_∩)O~

8.結果展示:

9.軟件打包

1.思考一個問題:為什么要打包?

        通俗來說,因為用戶可能沒有Qt SDK,可能有也不知道如何使用,所以需要打包(不同意的同志不要笑)。

2.打包工具:

3.打包原料:1.qt生成的可執行文件(一般使用release版的,因為其占用空間少,使用debug對應用戶來說沒必要,其占用空間也大)

            2.qt的一些dll(如果不知道你的可執行程序需要那些,就運行可執行程序根據提示去安裝目錄下的bin文件夾復制過來就行。eg. C:\Qt\Qt5.5.0\5.5\mingw492_32\bin)

    4.打包步驟:

  1. 把程序用到的資源,可執行程序、相關dll放置一個文件夾里

  2. 打開打包工具,

    完成后可以發給用戶了。

10.上代碼:

KelySerialPort.pro(項目文件)

#-------------------------------------------------

#

# Project created by QtCreator 2015-10-01T15:33:42

#

#-------------------------------------------------

 

QT += core gui serialport

 

greaterThan(QT_MAJOR_VERSION, 4): QT += widgets

 

TARGET = KelySerialPort

TEMPLATE = app

 

 

SOURCES += main.cpp \

KelySerialPort.cpp

 

HEADERS += \

KelySerialPort.h

 

DISTFILES += \

Readme.txt

RC_FILE += app.rc

 

KelySerialPort.h(頭文件):

#ifndef WIDGET_H
			

#define WIDGET_H 

 

#include <QWidget> 

#include <QTime> 

#include <QTimer> 

#include <QDebug> 

#include <QWidget> 

#include <QPushButton> 

#include <QLineEdit> 

#include <QLabel> 

#include <QGridLayout> 

#include <QtDebug> 

#include <QComboBox> 

#include <QMessageBox> 

#include <QtGui> 

#include <QTableView> 

#include <QHeaderView> 

#include <QTextEdit> 

#include <QTextBrowser> 

 

#include <QtSerialPort/QSerialPort> 

 

 

class PositionShow : public QWidget 

{
			

 Q_OBJECT 

 

public: 

 PositionShow(QWidget *parent = 0); 

 ~PositionShow(); 

 QPushButton * pb0; 

 QPushButton * pb1; 

 QPushButton * pb2; 

 QPushButton * pb3; 

 QGridLayout * gl0; 

 

 #define Posi0_0 "carport0" 

 #define Posi0_1 "carport1" 

 #define Posi1_0 "carport2" 

 #define Posi1_1 "carport3" 

 

public slots: 

};
			

 

 

class MySerialPort : public QWidget 

{
			

 Q_OBJECT 

 

public: 

 MySerialPort(QWidget *parent = 0); 

 ~MySerialPort(); 

 QHBoxLayout * hl0; 

 QHBoxLayout * hl1; 

 QHBoxLayout * hl2; 

 QHBoxLayout * hl3; 

 QHBoxLayout * hl4; 

 QHBoxLayout * hl5; 

 QHBoxLayout * hl6; 

 QHBoxLayout * hl7; 

 QHBoxLayout * hl8; 

 

 QVBoxLayout * vl0; 

 QVBoxLayout * vl1; 

 

 QGridLayout * gl0; 

 

 QLabel * lb0; 

 QLabel * lb1; 

 QLabel * lb2; 

 QLabel * lb3; 

 QLabel * lb4; 

 QLabel * lb5; 

 QLabel * lb6; 

 

 QComboBox * cb0; 

 QComboBox * cb1; 

 QComboBox * cb2; 

 QComboBox * cb3; 

 QComboBox * cb4; 

 

 QPushButton * pb0; 

 QPushButton * pb1; 

 QPushButton * pb2; 

 QPushButton * pb3; 

 QPushButton * pb4; 

 

 QTextEdit* te0; 

 QLineEdit* le0; 

 

public slots: 

 bool readFromSerial(void); 

 bool sendToSerial(void); 

 void openSerial(void); 

 void clearSendArea(void); 

 void clearGetArea(void); 

 void saveData(void); 

 

 

 

 

public: 

 QSerialPort serial; 

 QByteArray readBuf; 

 QTimer timer; 

 QString msg; 

 void UIload(void); 

 void UIlayout(void); 

 void setBaudRate(void); 

 void setDataBit(void); 

 void setParity(void); 

 void setStopBits(void); 

 void setComponemtAttribute(void); 

};
			

 

 

class Widget : public QWidget 

{
			

 Q_OBJECT 

 

public: 

 Widget(QWidget *parent = 0); 

 ~Widget(); 

 

 QGridLayout * gl_tab; 

 QTabWidget * QTab_UI; 

 MySerialPort * QTab_SerP; 

 PositionShow * QTab_PosiUI; 

 QWidget * help; 

 QTextBrowser * tw0; 

 QVBoxLayout * v0_for_help; 

 QTimer *timer; 

public slots: 

 void showEmptyPosi(void); 

public: 

 void loadDocument(void); 

};
			

 

#endif // WIDGET_H 

 

KelySerialPort.cpp(正文):

#include "KelySerialPort.h"

#include <QFile>

#include <QTextStream>

#include <QtSerialPort/QSerialPortInfo>

#include <QTime>

#include <QDate>

#include <QTimer>

#include <QString>

#include <QComboBox>

 

Widget::Widget(QWidget *parent)

: QWidget(parent)

{

this->setWindowTitle(tr("上位機:空位顯示"));

QTab_UI= new QTabWidget;

QTab_SerP = new MySerialPort;

QTab_PosiUI = new PositionShow;

help = new QWidget;

 

gl_tab = new QGridLayout;

v0_for_help = new QVBoxLayout;

QTab_UI->addTab(QTab_SerP,tr("(&T)串口設置界面"));

QTab_UI->addTab(QTab_PosiUI,tr("(&S)車位顯示界面"));

QTab_UI->addTab(help,tr("(&H)幫助頁面"));

 

gl_tab->addWidget(QTab_UI);

gl_tab->setContentsMargins(0,0,0,0);

this->setLayout(gl_tab); // 為窗口設置布局

timer = new QTimer(this); // 定時器 1秒 用於更新車位的狀態

timer->start(1000);

connect(timer, SIGNAL(timeout()), this, SLOT(showEmptyPosi()));

 

loadDocument(); // 加載幫助界面的文檔

}

 

Widget::~Widget()

{

 

}

 

 

MySerialPort::MySerialPort(QWidget *parent)

{

UIload();

UIlayout();

setComponemtAttribute();

foreach (const QSerialPortInfo &info, QSerialPortInfo::availablePorts()) {

cb0->addItem(info.portName());

}

 

connect(pb0,SIGNAL(clicked(bool)),this,SLOT(openSerial()));

connect(pb3,SIGNAL(clicked(bool)),this,SLOT(sendToSerial()));

connect(&serial,SIGNAL(readyRead()),this,SLOT(readFromSerial()));

connect(pb1,SIGNAL(clicked(bool)),this,SLOT(clearSendArea()));

connect(pb4,SIGNAL(clicked(bool)),this,SLOT(clearGetArea()));

connect(pb2,SIGNAL(clicked(bool)),this,SLOT(saveData()));

}

 

MySerialPort::~MySerialPort()

{

 

}

 

bool MySerialPort::readFromSerial()

{

readBuf.append(serial.readAll());

te0->append(QString(readBuf));

msg = QString(readBuf);

readBuf.clear();

}

 

bool MySerialPort::sendToSerial()

{

serial.write(le0->text().toLocal8Bit());

}

 

void MySerialPort::openSerial()

{

 

 if(pb0->text()=="(&O)打開串口"){ 

 pb0->setText(tr("(&O)關閉串口")); 

 serial.setPortName(cb0->currentText()); 

 serial.open(QIODevice::ReadWrite); 

 setBaudRate(); 

 setDataBit(); 

 setParity(); 

 setStopBits(); 

 

 cb0->setEnabled(false); 

 cb1->setEnabled(false); 

 cb2->setEnabled(false); 

 cb3->setEnabled(false); 

 cb4->setEnabled(false); 

 }else{ 

 serial.close(); 

 pb0->setText(tr("(&O)打開串口")); 

 cb0->setEnabled(true); 

 cb1->setEnabled(true); 

 cb2->setEnabled(true); 

 cb3->setEnabled(true); 

 cb4->setEnabled(true); 

 

 } 

 

}

 

void MySerialPort::clearSendArea()

{

te0->clear();

}

 

void MySerialPort::clearGetArea()

{

le0->clear();

}

 

void MySerialPort::saveData()

{ QTime tim;

qDebug()<<tim.currentTime().toString();

QDate td;

qDebug()<<td.currentDate().toString();

 

QFile data("SerialPortRecord.txt");

if (data.open(QFile::WriteOnly | QFile::Append)) {

QTextStream out(&data);

out<<"Save time:"<<td.currentDate().toString()<<" " \

<<tim.currentTime().toString()\

<<"\nData:"<<te0->document()->toPlainText()<<"\n\n";

}

}

 

void MySerialPort::UIload()

{

hl0 = new QHBoxLayout;

hl1 = new QHBoxLayout;

hl2 = new QHBoxLayout;

hl3 = new QHBoxLayout;

hl4 = new QHBoxLayout;

hl5 = new QHBoxLayout;

hl6 = new QHBoxLayout;

hl7 = new QHBoxLayout;

hl8 = new QHBoxLayout;

 

vl0 = new QVBoxLayout;

vl1 = new QVBoxLayout;

 

gl0 = new QGridLayout;

 

lb0 = new QLabel(tr("(&B)串口號:"));

lb1 = new QLabel(tr("(&V)波特率:"));

lb2 = new QLabel(tr("(&E)數據位:"));

lb3 = new QLabel(tr("(&P)停止位:"));

lb4 = new QLabel(tr("(&J)校驗位:"));

lb5 = new QLabel(tr("(&G)數據接收區:"));

lb6 = new QLabel(tr("(&D)數據發送區:"));

 

cb0 = new QComboBox;

cb1 = new QComboBox;

cb2 = new QComboBox;

cb3 = new QComboBox;

cb4 = new QComboBox;

 

pb0 = new QPushButton(tr("(&O)打開串口"));

pb1 = new QPushButton(tr("(&L)清空數據發送區"));

pb2 = new QPushButton(tr("(&A)保存數據"));

pb3 = new QPushButton(tr("(&E)發送數據"));

pb4 = new QPushButton(tr("(&G)清空數據接收區"));

 

te0 = new QTextEdit;

le0 = new QLineEdit;

 

}

 

void MySerialPort::UIlayout()

{

hl0->addWidget(lb0);

hl0->addWidget(cb0);

hl1->addWidget(lb1);

hl1->addWidget(cb1);

hl2->addWidget(lb2);

hl2->addWidget(cb2);

hl3->addWidget(lb3);

hl3->addWidget(cb3);

hl4->addWidget(lb4);

hl4->addWidget(cb4);

 

hl5->addWidget(pb1);

hl5->addWidget(pb2);

hl6->addWidget(pb3);

hl6->addWidget(pb4);

 

vl0->addWidget(pb0);

vl0->addLayout(hl0);

vl0->addLayout(hl1);

vl0->addLayout(hl2);

vl0->addLayout(hl3);

vl0->addLayout(hl4);

 

 

vl1->addWidget(lb6);

vl1->addLayout(hl6);

vl1->addWidget(le0);

vl1->addWidget(lb5);

vl1->addLayout(hl5);

vl1->addWidget(te0);

 

gl0->addLayout(vl0,0,0);

gl0->addLayout(vl1,0,1);

gl0->setSpacing(20);

this->setLayout(gl0);

 

}

 

void MySerialPort::setBaudRate()

{

if(cb1->currentText() == tr("9600"))

serial.setBaudRate(QSerialPort::Baud9600);

else if(cb1->currentText() == tr("1200"))

serial.setBaudRate(QSerialPort::Baud1200);

else if(cb1->currentText() == tr("2400"))

serial.setBaudRate(QSerialPort::Baud2400);

else if(cb1->currentText() == tr("4800"))

serial.setBaudRate(QSerialPort::Baud4800);

else if(cb1->currentText() == tr("19200"))

serial.setBaudRate(QSerialPort::Baud19200);

else if(cb1->currentText() == tr("38400"))

serial.setBaudRate(QSerialPort::Baud38400);

else if(cb1->currentText() == tr("57600"))

serial.setBaudRate(QSerialPort::Baud57600);

else if(cb1->currentText() == tr("115200"))

serial.setBaudRate(QSerialPort::Baud115200);

}

 

void MySerialPort::setDataBit()

{

if(cb2->currentText() == tr("Data5"))

serial.setDataBits(QSerialPort::Data5);

else if(cb2->currentText() == tr("Data6"))

serial.setDataBits(QSerialPort::Data6);

else if(cb2->currentText() == tr("Data7"))

serial.setDataBits(QSerialPort::Data7);

else if(cb2->currentText() == tr("Data8"))

serial.setDataBits(QSerialPort::Data8);

}

 

void MySerialPort::setParity()

{

if(cb4->currentText() == tr("NoParity"))

serial.setParity(QSerialPort::NoParity);

else if(cb4->currentText() == tr("EvenParity"))

serial.setParity(QSerialPort::EvenParity);

else if(cb4->currentText() == tr("OddParity"))

serial.setParity(QSerialPort::OddParity);

else if(cb4->currentText() == tr("SpaceParity"))

serial.setParity(QSerialPort::SpaceParity);

else if(cb4->currentText() == tr("MarkParity"))

serial.setParity(QSerialPort::MarkParity);

}

 

void MySerialPort::setStopBits()

{

if(cb3->currentText() == tr("OneStop"))

serial.setStopBits(QSerialPort::OneStop);

else if(cb3->currentText() == tr("OneAndHalfStop"))

serial.setStopBits(QSerialPort::OneAndHalfStop);

else if(cb3->currentText() == tr("TwoStop"))

serial.setStopBits(QSerialPort::TwoStop);

}

 

void MySerialPort::setComponemtAttribute()

{

cb1->addItem(tr("9600"));

cb1->addItem(tr("1200"));

cb1->addItem(tr("2400"));

cb1->addItem(tr("4800"));

cb1->addItem(tr("19200"));

cb1->addItem(tr("38400"));

cb1->addItem(tr("57600"));

cb1->addItem(tr("115200"));

 

cb2->addItem(tr("Data8"));

cb2->addItem(tr("Data5"));

cb2->addItem(tr("Data6"));

cb2->addItem(tr("Data7"));

 

cb3->addItem(tr("OneStop"));

cb3->addItem(tr("OneAndHalfStop"));

cb3->addItem(tr("TwoStop"));

 

cb4->addItem(tr("NoParity"));

cb4->addItem(tr("EvenParity"));

cb4->addItem(tr("OddParity"));

cb4->addItem(tr("SpaceParity"));

cb4->addItem(tr("MarkParity"));

 

pb0->setFixedWidth(120);

pb1->setFixedWidth(120);

pb2->setFixedWidth(120);

pb3->setFixedWidth(120);

pb4->setFixedWidth(120);

 

te0->setEnabled(false);

cb0->setFixedWidth(100);

cb1->setFixedWidth(100);

cb2->setFixedWidth(100);

cb3->setFixedWidth(100);

cb4->setFixedWidth(100);

 

lb5->setBuddy(te0);

lb6->setBuddy(le0);

 

lb0->setBuddy(cb0);

lb1->setBuddy(cb1);

lb2->setBuddy(cb2);

lb3->setBuddy(cb3);

lb4->setBuddy(cb4);

}

 

 

PositionShow::PositionShow(QWidget *parent)

{

gl0 = new QGridLayout;

pb0 = new QPushButton(tr("無車"));

pb1 = new QPushButton(tr("無車"));

pb2 = new QPushButton(tr("無車"));

pb3 = new QPushButton(tr("無車"));

 

pb0->setFixedSize(250,250);

pb1->setFixedSize(250,250);

pb2->setFixedSize(250,250);

pb3->setFixedSize(250,250);

 

gl0->addWidget(pb0,0,0);

gl0->addWidget(pb1,0,1);

gl0->addWidget(pb2,1,0);

gl0->addWidget(pb3,1,1);

 

pb0->setStyleSheet(QString::fromUtf8("font: 75 36pt \"\351\273\221\344\275\223\";"));

pb1->setStyleSheet(QString::fromUtf8("font: 75 36pt \"\351\273\221\344\275\223\";"));

pb2->setStyleSheet(QString::fromUtf8("font: 75 36pt \"\351\273\221\344\275\223\";"));

pb3->setStyleSheet(QString::fromUtf8("font: 75 36pt \"\351\273\221\344\275\223\";"));

setLayout(gl0);

}

 

PositionShow::~PositionShow()

{

 

}

 

void Widget::showEmptyPosi()

{

QString str = QTab_SerP->msg;

if(str == "END_A_0")

QTab_PosiUI->pb0->setText(tr("空車位:\n0個"));

if(str == "END_A_1")

QTab_PosiUI->pb0->setText(tr("空車位:\n1個"));

if(str == "END_A_2")

QTab_PosiUI->pb0->setText(tr("空車位:\n2個"));

 

if(str == "END_B_0")

QTab_PosiUI->pb1->setText(tr("空車位:\n0個"));

if(str == "END_B_1")

QTab_PosiUI->pb1->setText(tr("空車位:\n1個"));

 

if(str == "END_C_0")

QTab_PosiUI->pb2->setText(tr("空車位:\n0個"));

if(str == "END_C_1")

QTab_PosiUI->pb2->setText(tr("空車位:\n1個"));

 

if(str == "END_D_0")

QTab_PosiUI->pb3->setText(tr("空車位:\n0個"));

if(str == "END_D_1")

QTab_PosiUI->pb3->setText(tr("空車位:\n1個"));

}

 

void Widget::loadDocument()

{

tw0 = new QTextBrowser;

v0_for_help->addWidget(tw0);

help->setLayout(v0_for_help);

QByteArray str;

QFile file("Readme.txt");

if(file.open(QFile::ReadOnly)){

str.append(file.readAll());

file.close();

}

tw0->setText(str);

}

 

main.cpp(主函數):

#include "KelySerialPort.h" 

#include <QApplication> 

 

int main(int argc, char *argv[]) 

{
			

 QApplication a(argc, argv); 

 Widget w; 

 w.show(); 

 

 return a.exec(); 

}
			

Readme.txt(相關的。。):

1.enum QSerialPort::StopBits:

The default value is OneStop, i.e. 1 stop bit.

Constant    Value    Description

QSerialPort::OneStop    1    1 stop bit.

QSerialPort::OneAndHalfStop    3    1.5 stop bits. This is only for the Windows platform.

QSerialPort::TwoStop    2    2 stop bits.

QSerialPort::UnknownStopBits    -1    Unknown number of stop bits. This value is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

 

2.enum QSerialPort::Parity

The default value is NoParity, i.e. no parity.

Constant    Value    Description

QSerialPort::NoParity    0    No parity bit it sent. This is the most common parity setting. Error detection is handled by the communication protocol.

QSerialPort::EvenParity    2    The number of 1 bits in each character, including the parity bit, is always even.

QSerialPort::OddParity    3    The number of 1 bits in each character, including the parity bit, is always odd. It ensures that at least one state transition occurs in each character.

QSerialPort::SpaceParity    4    Space parity. The parity bit is sent in the space signal condition. It does not provide error detection information.

QSerialPort::MarkParity    5    Mark parity. The parity bit is always set to the mark signal condition (logical 1). It does not provide error detection information.

QSerialPort::UnknownParity    -1    Unknown parity. This value is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

 

3.enum QSerialPort::DataBits

The default value is Data8, i.e. 8 data bits.

This enum describes the number of data bits used.

 

Constant    Value    Description

QSerialPort::Data5    5    The number of data bits in each character is 5. It is used for Baudot code. It generally only makes sense with older equipment such as teleprinters.

QSerialPort::Data6    6    The number of data bits in each character is 6. It is rarely used.

QSerialPort::Data7    7    The number of data bits in each character is 7. It is used for true ASCII. It generally only makes sense with older equipment such as teleprinters.

QSerialPort::Data8    8    The number of data bits in each character is 8. It is used for most kinds of data, as this size matches the size of a byte. It is almost universally used in newer applications.

QSerialPort::UnknownDataBits    -1    Unknown number of bits. This value is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

 

4.enum QSerialPort::BaudRate

The default value is Baud9600, i.e. 9600 bits per second.

This enum describes the baud rate which the communication device operates with.

 

Note: Only the most common standard baud rates are listed in this enum.

 

Constant    Value    Description

QSerialPort::Baud1200    1200    1200 baud.

QSerialPort::Baud2400    2400    2400 baud.

QSerialPort::Baud4800    4800    4800 baud.

QSerialPort::Baud9600    9600    9600 baud.

QSerialPort::Baud19200    19200    19200 baud.

QSerialPort::Baud38400    38400    38400 baud.

QSerialPort::Baud57600    57600    57600 baud.

QSerialPort::Baud115200    115200    115200 baud.

QSerialPort::UnknownBaud    -1    Unknown baud. This value is obsolete. It is provided to keep old source code working. We strongly advise against using it in new code.

 

 

通信協議?


			
 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM