Python Qt GUI设计:做一款串口调试助手(实战篇—1)
目錄
1、UI設(shè)計(jì)
2、將UI文件轉(zhuǎn)換為Py文件
3、邏輯功能實(shí)現(xiàn)
3.1、初始化程序
3.2、串口檢測(cè)程序
3.3、?設(shè)置及打開(kāi)串口程序
3.4、定時(shí)發(fā)送數(shù)據(jù)程序
3.5、發(fā)送數(shù)據(jù)程序
3.6、接收數(shù)據(jù)程序
3.7、保存日志程序
3.8、加載日志程序
3.9、打開(kāi)博客、公眾號(hào)程序
3.10、清除發(fā)送和接收數(shù)據(jù)顯示程序
3.11、關(guān)閉串口程序
Python Qt GUI設(shè)計(jì)系列博文終于到了實(shí)戰(zhàn)篇,本篇博文將貫穿之前的基礎(chǔ)知識(shí)點(diǎn)實(shí)現(xiàn)一款串口調(diào)試助手。
關(guān)注【公眾號(hào)】 美男子玩編程,回復(fù)關(guān)鍵字:串口調(diào)試助手,獲取項(xiàng)目源碼~
資源下載:PythonQt串口調(diào)試助手-嵌入式文檔類(lèi)資源-CSDN下載
1、UI設(shè)計(jì)
UI設(shè)計(jì)使用Qt Creator實(shí)現(xiàn),組件布局如下所示:
2、將UI文件轉(zhuǎn)換為Py文件
這里使用Python腳本的方式將UI文件轉(zhuǎn)換為Python文件,代碼如下所示:
import os import os.pathdir ='./' #文件所在的路徑#找出路徑下所有的.ui文件 def listUiFile():list = []files = os.listdir(dir)for filename in files:#print(filename)if os.path.splitext(filename)[1] == '.ui':list.append(filename)return list#把擴(kuò)展名未.ui的轉(zhuǎn)換成.py的文件 def transPyFile(filename):return os.path.splitext(filename)[0] + '.py'#通過(guò)命令把.ui文件轉(zhuǎn)換成.py文件 def runMain():list = listUiFile()for uifile in list:pyfile = transPyFile(uifile)cmd = 'pyuic5 -o {pyfile} {uifile}'.format(pyfile=pyfile, uifile=uifile)os.system(cmd)if __name__ =="__main__":runMain()3、邏輯功能實(shí)現(xiàn)
3.1、初始化程序
首先初始化一些組件和標(biāo)志位的狀態(tài),設(shè)置信號(hào)與槽的關(guān)系,實(shí)現(xiàn)代碼如下所示:
# 初始化程序def __init__(self):super(Pyqt5_Serial, self).__init__()self.setupUi(self)self.init()self.ser = serial.Serial()self.port_check()# 設(shè)置Logo和標(biāo)題self.setWindowIcon(QIcon('Com.png'))self.setWindowTitle("串口調(diào)試助手 【公眾號(hào)】美男子玩編程")# 設(shè)置禁止拉伸窗口大小self.setFixedSize(self.width(), self.height())# 發(fā)送數(shù)據(jù)和接收數(shù)據(jù)數(shù)目置零self.data_num_sended = 0self.Lineedit2.setText(str(self.data_num_sended))self.data_num_received = 0self.Lineedit3.setText(str(self.data_num_received))# 串口關(guān)閉按鈕使能關(guān)閉self.Pushbuttom3.setEnabled(False)# 發(fā)送框、文本框清除self.Text1.setText("")self.Text2.setText("")# 建立控件信號(hào)與槽關(guān)系def init(self):# 串口檢測(cè)按鈕self.Pushbuttom2.clicked.connect(self.port_check)# 串口打開(kāi)按鈕self.Pushbuttom1.clicked.connect(self.port_open)# 串口關(guān)閉按鈕self.Pushbuttom3.clicked.connect(self.port_close)# 定時(shí)發(fā)送數(shù)據(jù)self.timer_send = QTimer()self.timer_send.timeout.connect(self.data_send)self.Checkbox7.stateChanged.connect(self.data_send_timer)# 發(fā)送數(shù)據(jù)按鈕self.Pushbuttom6.clicked.connect(self.data_send)# 加載日志self.Pushbuttom4.clicked.connect(self.savefiles)# 加載日志self.Pushbuttom5.clicked.connect(self.openfiles)# 跳轉(zhuǎn)鏈接self.commandLinkButton1.clicked.connect(self.link)# 清除發(fā)送按鈕self.Pushbuttom7.clicked.connect(self.send_data_clear)# 清除接收按鈕self.Pushbuttom8.clicked.connect(self.receive_data_clear)3.2、串口檢測(cè)程序
檢測(cè)電腦上所有串口,實(shí)現(xiàn)代碼如下所示:
# 串口檢測(cè)def port_check(self):# 檢測(cè)所有存在的串口,將信息存儲(chǔ)在字典中self.Com_Dict = {}port_list = list(serial.tools.list_ports.comports())self.Combobox1.clear()for port in port_list:self.Com_Dict["%s" % port[0]] = "%s" % port[1]self.Combobox1.addItem(port[0])# 無(wú)串口判斷if len(self.Com_Dict) == 0:self.Combobox1.addItem("無(wú)串口")3.3、?設(shè)置及打開(kāi)串口程序
檢測(cè)到串口后進(jìn)行配置,打開(kāi)串口,并且啟動(dòng)定時(shí)器一直接收用戶輸入,實(shí)現(xiàn)代碼如下所示:
# 打開(kāi)串口def port_open(self):self.ser.port = self.Combobox1.currentText() # 串口號(hào)self.ser.baudrate = int(self.Combobox2.currentText()) # 波特率flag_data = int(self.Combobox3.currentText()) # 數(shù)據(jù)位if flag_data == 5:self.ser.bytesize = serial.FIVEBITSelif flag_data == 6:self.ser.bytesize = serial.SIXBITSelif flag_data == 7:self.ser.bytesize = serial.SEVENBITSelse:self.ser.bytesize = serial.EIGHTBITSflag_data = self.Combobox4.currentText() # 校驗(yàn)位if flag_data == "None":self.ser.parity = serial.PARITY_NONEelif flag_data == "Odd":self.ser.parity = serial.PARITY_ODDelse:self.ser.parity = serial.PARITY_EVENflag_data = int(self.Combobox5.currentText()) # 停止位if flag_data == 1:self.ser.stopbits = serial.STOPBITS_ONEelse:self.ser.stopbits = serial.STOPBITS_TWOflag_data = self.Combobox6.currentText() # 流控if flag_data == "No Ctrl Flow":self.ser.xonxoff = False #軟件流控self.ser.dsrdtr = False #硬件流控 DTRself.ser.rtscts = False #硬件流控 RTSelif flag_data == "SW Ctrl Flow":self.ser.xonxoff = True #軟件流控else: if self.Checkbox3.isChecked():self.ser.dsrdtr = True #硬件流控 DTRif self.Checkbox4.isChecked():self.ser.rtscts = True #硬件流控 RTStry:time.sleep(0.1)self.ser.open()except:QMessageBox.critical(self, "串口異常", "此串口不能被打開(kāi)!")return None# 串口打開(kāi)后,切換開(kāi)關(guān)串口按鈕使能狀態(tài),防止失誤操作 if self.ser.isOpen():self.Pushbuttom1.setEnabled(False)self.Pushbuttom3.setEnabled(True)self.formGroupBox1.setTitle("串口狀態(tài)(開(kāi)啟)")# 定時(shí)器接收數(shù)據(jù)self.timer = QTimer()self.timer.timeout.connect(self.data_receive)# 打開(kāi)串口接收定時(shí)器,周期為1msself.timer.start(1)3.4、定時(shí)發(fā)送數(shù)據(jù)程序
通過(guò)定時(shí)器,可支持1ms至30s之間數(shù)據(jù)定時(shí),實(shí)現(xiàn)代碼如下所示:
# 定時(shí)發(fā)送數(shù)據(jù)def data_send_timer(self):try:if 1<= int(self.Lineedit1.text()) <= 30000: # 定時(shí)時(shí)間1ms~30s內(nèi)if self.Checkbox7.isChecked():self.timer_send.start(int(self.Lineedit1.text()))self.Lineedit1.setEnabled(False)else:self.timer_send.stop()self.Lineedit1.setEnabled(True)else:QMessageBox.critical(self, '定時(shí)發(fā)送數(shù)據(jù)異常', '定時(shí)發(fā)送數(shù)據(jù)周期僅可設(shè)置在30秒內(nèi)!')except:QMessageBox.critical(self, '定時(shí)發(fā)送數(shù)據(jù)異常', '請(qǐng)?jiān)O(shè)置正確的數(shù)值類(lèi)型!')3.5、發(fā)送數(shù)據(jù)程序
可以發(fā)送ASCII字符和十六進(jìn)制類(lèi)型數(shù)據(jù),并且可以在數(shù)據(jù)前顯示發(fā)送的時(shí)間,在數(shù)據(jù)后進(jìn)行換行,發(fā)送一個(gè)字節(jié),TX標(biāo)志會(huì)自動(dòng)累加,實(shí)現(xiàn)代碼如下所示:
# 發(fā)送數(shù)據(jù)def data_send(self):if self.ser.isOpen():input_s = self.Text2.toPlainText()# 判斷是否為非空字符串if input_s != "":# 時(shí)間顯示if self.Checkbox5.isChecked():self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ")# HEX發(fā)送if self.Checkbox1.isChecked(): input_s = input_s.strip()send_list = []while input_s != '':try:num = int(input_s[0:2], 16)except ValueError:QMessageBox.critical(self, '串口異常', '請(qǐng)輸入規(guī)范十六進(jìn)制數(shù)據(jù),以空格分開(kāi)!')return Noneinput_s = input_s[2:].strip()send_list.append(num)input_s = bytes(send_list)# ASCII發(fā)送else: input_s = (input_s).encode('utf-8')# HEX接收顯示if self.Checkbox2.isChecked(): out_s = ''for i in range(0, len(input_s)):out_s = out_s + '{:02X}'.format(input_s[i]) + ' 'self.Text1.insertPlainText(out_s)# ASCII接收顯示else: self.Text1.insertPlainText(input_s.decode('utf-8')) # 接收換行 if self.Checkbox6.isChecked():self.Text1.insertPlainText('\r\n')# 獲取到Text光標(biāo)textCursor = self.Text1.textCursor()# 滾動(dòng)到底部textCursor.movePosition(textCursor.End)# 設(shè)置光標(biāo)到Text中去self.Text1.setTextCursor(textCursor)# 統(tǒng)計(jì)發(fā)送字符數(shù)量num = self.ser.write(input_s)self.data_num_sended += numself.Lineedit2.setText(str(self.data_num_sended))else:pass3.6、接收數(shù)據(jù)程序
可以接收ASCII字符和十六進(jìn)制類(lèi)型數(shù)據(jù),并且可以在數(shù)據(jù)前顯示發(fā)送的時(shí)間,在數(shù)據(jù)后進(jìn)行換行,接收一個(gè)字節(jié),RX標(biāo)志會(huì)自動(dòng)累加,實(shí)現(xiàn)代碼如下所示:
# 接收數(shù)據(jù)def data_receive(self):try:num = self.ser.inWaiting()if num > 0:time.sleep(0.1)num = self.ser.inWaiting() #延時(shí),再讀一次數(shù)據(jù),確保數(shù)據(jù)完整性except:QMessageBox.critical(self, '串口異常', '串口接收數(shù)據(jù)異常,請(qǐng)重新連接設(shè)備!')self.port_close()return Noneif num > 0:data = self.ser.read(num)num = len(data)# 時(shí)間顯示if self.Checkbox5.isChecked():self.Text1.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ")# HEX顯示數(shù)據(jù)if self.Checkbox2.checkState():out_s = ''for i in range(0, len(data)):out_s = out_s + '{:02X}'.format(data[i]) + ' 'self.Text1.insertPlainText(out_s)# ASCII顯示數(shù)據(jù)else:self.Text1.insertPlainText(data.decode('utf-8'))# 接收換行 if self.Checkbox6.isChecked():self.Text1.insertPlainText('\r\n')# 獲取到text光標(biāo)textCursor = self.Text1.textCursor()# 滾動(dòng)到底部textCursor.movePosition(textCursor.End)# 設(shè)置光標(biāo)到text中去self.Text1.setTextCursor(textCursor)# 統(tǒng)計(jì)接收字符的數(shù)量self.data_num_received += numself.Lineedit3.setText(str(self.data_num_received))else:pass3.7、保存日志程序
將接收框中收發(fā)的數(shù)據(jù)保存到TXT文本中,實(shí)現(xiàn)代碼如下所示:
# 保存日志def savefiles(self):dlg = QFileDialog()filenames = dlg.getSaveFileName(None, "保存日志文件", None, "Txt files(*.txt)")try:with open(file = filenames[0], mode='w', encoding='utf-8') as file:file.write(self.Text1.toPlainText())except:QMessageBox.critical(self, '日志異常', '保存日志文件失敗!')3.8、加載日志程序
加載保存到TXT文本中的數(shù)據(jù)信息到發(fā)送框中,實(shí)現(xiàn)代碼如下所示:
# 加載日志def openfiles(self):dlg = QFileDialog()filenames = dlg.getOpenFileName(None, "加載日志文件", None, "Txt files(*.txt)")try:with open(file = filenames[0], mode='r', encoding='utf-8') as file:self.Text2.setPlainText(file.read())except:QMessageBox.critical(self, '日志異常', '加載日志文件失敗!')3.9、打開(kāi)博客、公眾號(hào)程序
點(diǎn)擊按鈕,打開(kāi)我的公眾號(hào)二維碼和博客主頁(yè),實(shí)現(xiàn)代碼如下所示:
# 打開(kāi)博客鏈接和公眾號(hào)二維碼def link(self):dialog = QDialog()label_img = QLabel()label_img.setAlignment(Qt.AlignCenter) label_img.setPixmap(QPixmap("./img.jpg"))vbox = QVBoxLayout()vbox.addWidget(label_img)dialog.setLayout(vbox)dialog.setWindowTitle("快掃碼關(guān)注公眾號(hào)吧~")dialog.setWindowModality(Qt.ApplicationModal)dialog.exec_()webbrowser.open('https://blog.csdn.net/m0_38106923')3.10、清除發(fā)送和接收數(shù)據(jù)顯示程序
清除發(fā)送數(shù)據(jù)框和接收數(shù)據(jù)框的內(nèi)容和計(jì)數(shù)次數(shù),實(shí)現(xiàn)代碼如下所示:
# 清除發(fā)送數(shù)據(jù)顯示def send_data_clear(self):self.Text2.setText("")self.data_num_sended = 0self.Lineedit2.setText(str(self.data_num_sended))# 清除接收數(shù)據(jù)顯示def receive_data_clear(self):self.Text1.setText("")self.data_num_received = 0self.Lineedit3.setText(str(self.data_num_received))3.11、關(guān)閉串口程序
關(guān)閉串口,停止定時(shí)器,重置組件和標(biāo)志狀態(tài),實(shí)現(xiàn)代碼如下所示:
# 關(guān)閉串口def port_close(self):try:self.timer.stop()self.timer_send.stop()self.ser.close()except:QMessageBox.critical(self, '串口異常', '關(guān)閉串口失敗,請(qǐng)重啟程序!')return None# 切換開(kāi)關(guān)串口按鈕使能狀態(tài)和定時(shí)發(fā)送使能狀態(tài)self.Pushbuttom1.setEnabled(True)self.Pushbuttom3.setEnabled(False)self.Lineedit1.setEnabled(True)# 發(fā)送數(shù)據(jù)和接收數(shù)據(jù)數(shù)目置零self.data_num_sended = 0self.Lineedit2.setText(str(self.data_num_sended))self.data_num_received = 0self.Lineedit3.setText(str(self.data_num_received))self.formGroupBox1.setTitle("串口狀態(tài)(關(guān)閉)")資源下載:PythonQt串口調(diào)試助手-嵌入式文檔類(lèi)資源-CSDN下載?
總結(jié)
以上是生活随笔為你收集整理的Python Qt GUI设计:做一款串口调试助手(实战篇—1)的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。
- 上一篇: 毕业论文排版素材大学计算机基础,毕业论文
- 下一篇: python battleship_一个