邏輯文件
import sys import serial import serial.tools.list_ports from Ui_day13_test01 import Ui_mainWindow from PyQt5.QtWidgets import QMainWindow,QApplication,QMessageBox from PyQt5.QtCore import QTimer # AttributeError: 'Pyqt5_Serial' object has no attribute 'setCentralWidget'的解決方法 class PyqtSerial(QMainWindow,Ui_mainWindow): def __init__(self): super().__init__() # 用super繼承父類中的__init__()方法 # 因為前面Ui程序中mainWindow = QtWidgets.QMainWindow(),而在邏輯文件中self是 # 指myshow對象,相當於就是用用myshow來設置界面 self.setupUi(self) self.start() self.setWindowTitle('我的串口小助手') # 更改軟件標題名稱 self.ser=serial.Serial() # 調用串口模塊 # 接收數據和發送數據數目置零 self.data_num_received = 0 self.recv_byte.setText(str(self.data_num_received)) self.data_num_sended = 0 self.send_byte.setText(str(self.data_num_sended)) # 函數執行條件變量 self.com_check=False # 判斷串口是否檢查 # 設置界面啟動函數 def start(self): self.state_label.setText('請點擊【檢測串口】按鈕!') # 串口檢測按鈕 self.ser_test.clicked.connect(self.portCheck) # 串口信息顯示 self.com_port.currentTextChanged.connect(self.portImf) # 打開串口按鈕 self.open_ser.clicked.connect(self.portOpen) # 關閉串口按鈕 self.close_ser.clicked.connect(self.portClose) # 發送數據按鈕 self.send_botton.clicked.connect(self.dataSend) # 發送定時器發送數據 self.timer_send=QTimer() # 括號內可以加self,也可以不加 self.timer_send.timeout.connect(self.dataSend) # 每次計時結束,觸發括號內的函數 self.time_send.stateChanged.connect(self.dataTimerSend) # QCheckBox選擇框改變后連接括號內的函數 # 接收定時器接收數據 # 程序先運行start函數,然后運行到這個定時器時,就不操作了,只要界面上有操作, # 並且該操作對應的函數里有self.timer.start()開始計時的代碼,則當計時結束后, # 就會觸發此定時器后面的函數 self.timer=QTimer() # 創建一個定時器 self.timer.timeout.connect(self.dataReceive) # 每次計時結束,觸發括號內的函數 # 清除發送窗口 self.send_clear.clicked.connect(self.sendDataClear) # 清除接收窗口 self.recv_clear.clicked.connect(self.receiveDataClear) # 清除發送窗口 def sendDataClear(self): self.send_data.setText('') # 清除接收窗口 def receiveDataClear(self): self.recv_data.setText('') # 定時發送數據 def dataTimerSend(self): if self.time_send.isChecked(): # 檢查time_send的QCheckBox是否勾選上 self.timer_send.start(int(self.time_num.text())) # 計時器按time_num值開始計時 self.time_num.setEnabled(False) # time_num的QLineEdit不選中 else: self.timer_send.stop() # 發送計時器停止 self.time_num.setEnabled(True) # # time_num的QLineEdit選中 # 發送數據 def dataSend(self): if self.ser.isOpen(): # 判斷串口是否打開 input_s=self.send_data.toPlainText() # 將發送文本框中的內容賦值給變量 if input_s !='': # 判斷發送文本框中有內容 # 非空字符串 if self.send_hex.isChecked(): # 判斷hex的QCheckBox勾選上了 # hex發送 input_s=input_s.strip() # 去掉發送文本框內容前后的空格、回車等 send_list=[] # 創建一個發送列表 while input_s !='': # 發送內容變量不為空 try: # >>> int('12',base=16) # 如果是帶參數base的話,12要以字符串的形式進行輸入,12 為 16進制 # 18 num=int(input_s[0:2],16) # 將發送內容的前兩位轉換成16進制 except ValueError: QMessageBox.critical(self,'wrong data','請輸入十六進制數據,以空格分開!') return input_s=input_s[2:].strip() # 切割input_s中前兩位,並去掉前后空格,最后賦值到input_s send_list.append(num) # 將已經轉換的前兩位添加到發送列表中 input_s=bytes(send_list) # 將發送列表轉換成bytes else: # ascii發送 input_s=(input_s+'\r\n').encode('gbk') # 將發送內容按gbk格式編碼 num=self.ser.write(input_s) # 發送數據 self.data_num_sended+=num # 已發送內容計數 self.send_byte.setText(str(self.data_num_sended)) # 改變已發送計數框中的值 else: pass # 關閉串口 def portClose(self): self.timer.stop() # 接收定時器關閉 self.timer_send.stop() # 發送定時器關閉 try: self.ser.close() # 關閉串口 except: pass self.open_ser.setEnabled(True) # 設置按鈕QPushButton狀態為True self.close_ser.setEnabled(False) # 設置按鈕QPushButton狀態為False self.time_num.setEnabled(True) # QLineEdit恢復默認值 # 接收數據和發送數據數目置零 self.data_num_received=0 self.recv_byte.setText(str(self.data_num_received)) self.data_num_sended=0 self.send_byte.setText(str(self.data_num_sended)) self.groupBox_4.setTitle('串口狀態(已關閉)') # 改變串口狀態框的名稱 # 接收數據 def dataReceive(self): # self.timer.start(2000) # 此處設置的時間為2000毫秒,表示每間隔2000毫秒運行下面的print代碼 # print('數據接收中') try: num=self.ser.inWaiting() # 返回接收緩沖區中的字符數 except: self.portClose() # 關閉串口 return None if num>0: # 接收緩沖區中的字符數大於零時 data=self.ser.read(num) # 讀取全部數據 num=len(data) # 提取數據的字符長度 # hex顯示 if self.recv_hex.checkState(): # 判斷hex接收的QCheckBox是否選中 out_s='' for i in range(0,len(data)): # 循環遍歷接收到的數據 # X:輸出整數的大寫十六進制方式; out_s=out_s+'{:X}'.format(data[i])+' ' # 將字符轉換成整數的大寫十六進制方式 self.recv_data.insertPlainText(out_s) # 將轉換好的數據添加到接收數據文本框中 else: # 串口接收到的字符串為b'123',要轉化成unicode字符串才能輸出到窗口中去 self.recv_data.insertPlainText(data.decode('gbk')) # 統計接收字符的數量 self.data_num_received+=num # 將接收到的數據的長度數賦值給計數變量 self.recv_byte.setText(str(self.data_num_received)) # 將接收到的數據長度數顯示在計數文本框中 # 獲取到text光標 textCursor=self.recv_data.textCursor() # 滾動到底部 textCursor.movePosition(textCursor.End) # 設置光標到text中去 self.recv_data.setTextCursor(textCursor) else: pass # 打開串口 def portOpen(self): # try: # # 設置串口參數(此為網友代碼),運行出錯, # self.ser.port=self.com_port.currentText() # self.ser.baudrate=int(self.baudrate.currentText()) # self.ser.bytesize=int(self.data_bit.currentText()) # self.ser.stopbits=int(self.stop_bit.currentText()) # self.ser.parity=self.check_bit.currentText() # 出錯原因在這里,這個是不用的 # except Exception as e: # print('請先打開其它設置!',e) # 設置串口參數 self.ser.port = self.com_port.currentText() self.ser.baudrate = int(self.baudrate.currentText()) self.ser.bytesize = int(self.data_bit.currentText()) self.ser.stopbits = int(self.stop_bit.currentText()) try: self.ser.open() except: QMessageBox.critical(self,'Port Error','此串口不能被打開!') return None # return代表結束該函數執行,此處可以寫成return不加None # 打開串口接收定時器,周期為2ms self.timer.start(2) # 此處的意思是當2ms的時間到了之后,觸發括號內的dataReceive函數 if self.ser.isOpen(): self.open_ser.setEnabled(False) # 設置按鈕QPushButton狀態為False self.close_ser.setEnabled(True) # 設置按鈕QPushButton狀態為True self.groupBox_4.setTitle('串口狀態(已開啟)') # 串口信息 def portImf(self): if self.com_check: # 顯示選定的串口的詳細信息 imf_s=self.com_port.currentText() # 將串口選擇的當前內容賦值給變量 if imf_s !='': self.state_label.setText('串口{}選擇完成!'.format(self.com_port.currentText())) else: self.state_label.setText('請先點擊檢測串口按鈕!') # 串口檢查 def portCheck(self): # 檢測所有存在的串口,將信息存儲在字典中 self.com_dict={} # 創建一個空字典 port_list=list(serial.tools.list_ports.comports()) # 查找串口數據,並保存在列表中 self.com_port.clear() # 清空默認串口菜單數據 # 遍列串口數列表,並將com名稱重新添加到串口菜單中 for port in port_list: self.com_dict['%s'%port[0]]='%s'%port[1] self.com_port.addItem(port[0]) # 判斷串口是否找到 if len(self.com_dict)==0: self.state_label.setText('無串口!') else: self.state_label.setText('共有{}個串口,請選擇串口!'.format(len(self.com_dict))) self.com_check=True if __name__ == '__main__': app=QApplication(sys.argv) # 由於前面導入的是PyQt5.QtWidgets,而QApplication是該模塊里的一個類 myshow=PyqtSerial() # 根據類來創建一個對象 myshow.show() # 對象顯示 sys.exit(app.exec_())
界面文件
from PyQt5 import QtCore, QtGui, QtWidgets class Ui_mainWindow(object): def setupUi(self, mainWindow): mainWindow.setObjectName("mainWindow") mainWindow.resize(721, 490) mainWindow.setMinimumSize(QtCore.QSize(721, 490)) mainWindow.setMaximumSize(QtCore.QSize(721, 490)) self.centralWidget = QtWidgets.QWidget(mainWindow) self.centralWidget.setObjectName("centralWidget") self.widget = QtWidgets.QWidget(self.centralWidget) self.widget.setGeometry(QtCore.QRect(20, 20, 681, 451)) self.widget.setObjectName("widget") self.groupBox = QtWidgets.QGroupBox(self.widget) self.groupBox.setGeometry(QtCore.QRect(0, 0, 221, 311)) self.groupBox.setObjectName("groupBox") self.layoutWidget = QtWidgets.QWidget(self.groupBox) self.layoutWidget.setGeometry(QtCore.QRect(10, 20, 201, 281)) self.layoutWidget.setObjectName("layoutWidget") self.gridLayout = QtWidgets.QGridLayout(self.layoutWidget) self.gridLayout.setContentsMargins(0, 0, 0, 0) self.gridLayout.setObjectName("gridLayout") self.label_3 = QtWidgets.QLabel(self.layoutWidget) self.label_3.setObjectName("label_3") self.gridLayout.addWidget(self.label_3, 1, 0, 1, 1) self.label_4 = QtWidgets.QLabel(self.layoutWidget) self.label_4.setObjectName("label_4") self.gridLayout.addWidget(self.label_4, 2, 0, 1, 3) self.label_5 = QtWidgets.QLabel(self.layoutWidget) self.label_5.setObjectName("label_5") self.gridLayout.addWidget(self.label_5, 3, 0, 1, 1) self.label_6 = QtWidgets.QLabel(self.layoutWidget) self.label_6.setObjectName("label_6") self.gridLayout.addWidget(self.label_6, 4, 0, 1, 1) self.label_7 = QtWidgets.QLabel(self.layoutWidget) self.label_7.setObjectName("label_7") self.gridLayout.addWidget(self.label_7, 5, 0, 1, 1) self.label_8 = QtWidgets.QLabel(self.layoutWidget) self.label_8.setObjectName("label_8") self.gridLayout.addWidget(self.label_8, 6, 0, 1, 1) self.stop_bit = QtWidgets.QComboBox(self.layoutWidget) self.stop_bit.setObjectName("stop_bit") self.stop_bit.addItem("") self.stop_bit.addItem("") self.gridLayout.addWidget(self.stop_bit, 6, 1, 1, 2) self.open_ser = QtWidgets.QPushButton(self.layoutWidget) self.open_ser.setObjectName("open_ser") self.gridLayout.addWidget(self.open_ser, 7, 0, 1, 3) self.close_ser = QtWidgets.QPushButton(self.layoutWidget) self.close_ser.setObjectName("close_ser") self.gridLayout.addWidget(self.close_ser, 8, 0, 1, 3) self.com_port = QtWidgets.QComboBox(self.layoutWidget) self.com_port.setFocusPolicy(QtCore.Qt.WheelFocus) self.com_port.setObjectName("com_port") self.com_port.addItem("") self.com_port.addItem("") self.com_port.addItem("") self.com_port.addItem("") self.gridLayout.addWidget(self.com_port, 1, 1, 1, 2) self.label_2 = QtWidgets.QLabel(self.layoutWidget) self.label_2.setObjectName("label_2") self.gridLayout.addWidget(self.label_2, 0, 0, 1, 1) self.baudrate = QtWidgets.QComboBox(self.layoutWidget) self.baudrate.setObjectName("baudrate") self.baudrate.addItem("") self.baudrate.addItem("") self.gridLayout.addWidget(self.baudrate, 3, 1, 1, 2) self.data_bit = QtWidgets.QComboBox(self.layoutWidget) self.data_bit.setObjectName("data_bit") self.data_bit.addItem("") self.data_bit.addItem("") self.data_bit.addItem("") self.data_bit.addItem("") self.gridLayout.addWidget(self.data_bit, 4, 1, 1, 2) self.check_bit = QtWidgets.QComboBox(self.layoutWidget) self.check_bit.setObjectName("check_bit") self.check_bit.addItem("") self.check_bit.addItem("") self.gridLayout.addWidget(self.check_bit, 5, 1, 1, 2) self.ser_test = QtWidgets.QPushButton(self.layoutWidget) self.ser_test.setObjectName("ser_test") self.gridLayout.addWidget(self.ser_test, 0, 1, 1, 2) self.groupBox_2 = QtWidgets.QGroupBox(self.widget) self.groupBox_2.setGeometry(QtCore.QRect(250, 0, 321, 181)) self.groupBox_2.setObjectName("groupBox_2") self.recv_data = QtWidgets.QTextEdit(self.groupBox_2) self.recv_data.setGeometry(QtCore.QRect(10, 20, 301, 151)) self.recv_data.setObjectName("recv_data") self.groupBox_3 = QtWidgets.QGroupBox(self.widget) self.groupBox_3.setGeometry(QtCore.QRect(250, 200, 321, 181)) self.groupBox_3.setObjectName("groupBox_3") self.send_data = QtWidgets.QTextEdit(self.groupBox_3) self.send_data.setGeometry(QtCore.QRect(10, 20, 301, 151)) self.send_data.setObjectName("send_data") self.groupBox_4 = QtWidgets.QGroupBox(self.widget) self.groupBox_4.setGeometry(QtCore.QRect(0, 330, 221, 111)) self.groupBox_4.setObjectName("groupBox_4") self.layoutWidget1 = QtWidgets.QWidget(self.groupBox_4) self.layoutWidget1.setGeometry(QtCore.QRect(30, 20, 161, 51)) self.layoutWidget1.setObjectName("layoutWidget1") self.gridLayout_2 = QtWidgets.QGridLayout(self.layoutWidget1) self.gridLayout_2.setContentsMargins(0, 0, 0, 0) self.gridLayout_2.setObjectName("gridLayout_2") self.label_9 = QtWidgets.QLabel(self.layoutWidget1) self.label_9.setObjectName("label_9") self.gridLayout_2.addWidget(self.label_9, 0, 0, 1, 1) self.label_11 = QtWidgets.QLabel(self.layoutWidget1) self.label_11.setObjectName("label_11") self.gridLayout_2.addWidget(self.label_11, 1, 0, 1, 1) self.send_byte = QtWidgets.QLineEdit(self.layoutWidget1) self.send_byte.setObjectName("send_byte") self.gridLayout_2.addWidget(self.send_byte, 1, 2, 1, 1) self.recv_byte = QtWidgets.QLineEdit(self.layoutWidget1) self.recv_byte.setObjectName("recv_byte") self.gridLayout_2.addWidget(self.recv_byte, 0, 2, 1, 1) spacerItem = QtWidgets.QSpacerItem(80, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.gridLayout_2.addItem(spacerItem, 0, 1, 1, 1) self.state_label = QtWidgets.QLabel(self.groupBox_4) self.state_label.setGeometry(QtCore.QRect(20, 80, 181, 21)) self.state_label.setText("") self.state_label.setObjectName("state_label") self.recv_hex = QtWidgets.QCheckBox(self.widget) self.recv_hex.setGeometry(QtCore.QRect(590, 20, 91, 19)) self.recv_hex.setObjectName("recv_hex") self.send_hex = QtWidgets.QCheckBox(self.widget) self.send_hex.setGeometry(QtCore.QRect(590, 200, 91, 19)) self.send_hex.setObjectName("send_hex") self.recv_clear = QtWidgets.QPushButton(self.widget) self.recv_clear.setGeometry(QtCore.QRect(590, 50, 70, 30)) sizePolicy = QtWidgets.QSizePolicy(QtWidgets.QSizePolicy.Minimum, QtWidgets.QSizePolicy.Minimum) sizePolicy.setHorizontalStretch(0) sizePolicy.setVerticalStretch(0) sizePolicy.setHeightForWidth(self.recv_clear.sizePolicy().hasHeightForWidth()) self.recv_clear.setSizePolicy(sizePolicy) self.recv_clear.setStyleSheet("background-color: rgb(174, 255, 235);") self.recv_clear.setObjectName("recv_clear") self.send_botton = QtWidgets.QPushButton(self.widget) self.send_botton.setGeometry(QtCore.QRect(590, 230, 70, 30)) self.send_botton.setStyleSheet("background-color: rgb(174, 255, 235);") self.send_botton.setObjectName("send_botton") self.send_clear = QtWidgets.QPushButton(self.widget) self.send_clear.setGeometry(QtCore.QRect(590, 280, 70, 30)) self.send_clear.setStyleSheet("background-color: rgb(174, 255, 235);") self.send_clear.setObjectName("send_clear") self.layoutWidget2 = QtWidgets.QWidget(self.widget) self.layoutWidget2.setGeometry(QtCore.QRect(260, 400, 211, 23)) self.layoutWidget2.setObjectName("layoutWidget2") self.horizontalLayout = QtWidgets.QHBoxLayout(self.layoutWidget2) self.horizontalLayout.setContentsMargins(0, 0, 0, 0) self.horizontalLayout.setObjectName("horizontalLayout") self.time_send = QtWidgets.QCheckBox(self.layoutWidget2) self.time_send.setObjectName("time_send") self.horizontalLayout.addWidget(self.time_send) spacerItem1 = QtWidgets.QSpacerItem(40, 20, QtWidgets.QSizePolicy.Expanding, QtWidgets.QSizePolicy.Minimum) self.horizontalLayout.addItem(spacerItem1) self.time_num = QtWidgets.QLineEdit(self.layoutWidget2) self.time_num.setMinimumSize(QtCore.QSize(60, 0)) self.time_num.setMaximumSize(QtCore.QSize(60, 16777215)) self.time_num.setObjectName("time_num") self.horizontalLayout.addWidget(self.time_num) self.label = QtWidgets.QLabel(self.layoutWidget2) self.label.setObjectName("label") self.horizontalLayout.addWidget(self.label) mainWindow.setCentralWidget(self.centralWidget) self.retranslateUi(mainWindow) QtCore.QMetaObject.connectSlotsByName(mainWindow) def retranslateUi(self, mainWindow): _translate = QtCore.QCoreApplication.translate mainWindow.setWindowTitle(_translate("mainWindow", "串口小助手")) self.groupBox.setTitle(_translate("mainWindow", "串口設置")) self.label_3.setText(_translate("mainWindow", "串口選擇:")) self.label_4.setText(_translate("mainWindow", "Serial Port (COM1->COM2)")) self.label_5.setText(_translate("mainWindow", "波特率:")) self.label_6.setText(_translate("mainWindow", "數據位:")) self.label_7.setText(_translate("mainWindow", "校驗位:")) self.label_8.setText(_translate("mainWindow", "停止位:")) self.stop_bit.setItemText(0, _translate("mainWindow", "1")) self.stop_bit.setItemText(1, _translate("mainWindow", "2")) self.open_ser.setText(_translate("mainWindow", "打開串口")) self.close_ser.setText(_translate("mainWindow", "關閉串口")) self.com_port.setItemText(0, _translate("mainWindow", "COM1")) self.com_port.setItemText(1, _translate("mainWindow", "COM2")) self.com_port.setItemText(2, _translate("mainWindow", "COM3")) self.com_port.setItemText(3, _translate("mainWindow", "COM4")) self.label_2.setText(_translate("mainWindow", "串口檢測:")) self.baudrate.setItemText(0, _translate("mainWindow", "9600")) self.baudrate.setItemText(1, _translate("mainWindow", "115200")) self.data_bit.setItemText(0, _translate("mainWindow", "8")) self.data_bit.setItemText(1, _translate("mainWindow", "7")) self.data_bit.setItemText(2, _translate("mainWindow", "6")) self.data_bit.setItemText(3, _translate("mainWindow", "5")) self.check_bit.setItemText(0, _translate("mainWindow", "NONE")) self.check_bit.setItemText(1, _translate("mainWindow", "ODD")) self.ser_test.setText(_translate("mainWindow", "檢測串口")) self.groupBox_2.setTitle(_translate("mainWindow", "接收區")) self.groupBox_3.setTitle(_translate("mainWindow", "發送區")) self.groupBox_4.setTitle(_translate("mainWindow", "串口狀態")) self.label_9.setText(_translate("mainWindow", "已接收:")) self.label_11.setText(_translate("mainWindow", "已發送:")) self.send_byte.setText(_translate("mainWindow", "0")) self.recv_byte.setText(_translate("mainWindow", "0")) self.recv_hex.setText(_translate("mainWindow", "Hex接收")) self.send_hex.setText(_translate("mainWindow", "Hex發送")) self.recv_clear.setText(_translate("mainWindow", "清除")) self.send_botton.setText(_translate("mainWindow", "發送")) self.send_clear.setText(_translate("mainWindow", "清除")) self.time_send.setText(_translate("mainWindow", "定時發送")) self.time_num.setText(_translate("mainWindow", "1000")) self.label.setText(_translate("mainWindow", "ms/次")) if __name__ == "__main__": import sys app = QtWidgets.QApplication(sys.argv) mainWindow = QtWidgets.QMainWindow() ui = Ui_mainWindow() ui.setupUi(mainWindow) mainWindow.show() sys.exit(app.exec_())
以前就是參照網友設計的一個串口助手小工具。
如有問題,可關注微信公眾號進行咨詢!