<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          Python Qt GUI設(shè)計(jì):做一款串口調(diào)試助手(實(shí)戰(zhàn)篇—1)

          共 8709字,需瀏覽 18分鐘

           ·

          2022-01-08 13:25

          點(diǎn)擊上方藍(lán)色字體,關(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)目源碼~



          1


          UI設(shè)計(jì)



          UI設(shè)計(jì)使用Qt Creator實(shí)現(xiàn),組件布局如下所示:




          2


          將UI文件轉(zhuǎn)換為Py文件



          這里使用Python腳本的方式將UI文件轉(zhuǎn)換為Python文件,代碼如下所示:


          import osimport os.path
          dir ='./' #文件所在的路徑
          #找出路徑下所有的.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'
          #通過命令把.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 = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.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) # 串口打開按鈕 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])
          # 無串口判斷 if len(self.Com_Dict) == 0: self.Combobox1.addItem("無串口")


          3.3、?設(shè)置及打開串口程序


          檢測(cè)到串口后進(jìn)行配置,打開串口,并且啟動(dòng)定時(shí)器一直接收用戶輸入,實(shí)現(xiàn)代碼如下所示:


          # 打開串口    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.FIVEBITS elif flag_data == 6: self.ser.bytesize = serial.SIXBITS elif flag_data == 7: self.ser.bytesize = serial.SEVENBITS else: self.ser.bytesize = serial.EIGHTBITS
          flag_data = self.Combobox4.currentText() # 校驗(yàn)位 if flag_data == "None": self.ser.parity = serial.PARITY_NONE elif flag_data == "Odd": self.ser.parity = serial.PARITY_ODD else: self.ser.parity = serial.PARITY_EVEN
          flag_data = int(self.Combobox5.currentText()) # 停止位 if flag_data == 1: self.ser.stopbits = serial.STOPBITS_ONE else: self.ser.stopbits = serial.STOPBITS_TWO
          flag_data = self.Combobox6.currentText() # 流控 if flag_data == "No Ctrl Flow": self.ser.xonxoff = False #軟件流控 self.ser.dsrdtr = False #硬件流控 DTR self.ser.rtscts = False #硬件流控 RTS elif flag_data == "SW Ctrl Flow": self.ser.xonxoff = True #軟件流控 else: if self.Checkbox3.isChecked(): self.ser.dsrdtr = True #硬件流控 DTR if self.Checkbox4.isChecked(): self.ser.rtscts = True #硬件流控 RTS try: time.sleep(0.1) self.ser.open() except: QMessageBox.critical(self, "串口異常", "此串口不能被打開!") return None
          # 串口打開后,切換開關(guān)串口按鈕使能狀態(tài),防止失誤操作 if self.ser.isOpen(): self.Pushbuttom1.setEnabled(False) self.Pushbuttom3.setEnabled(True) self.formGroupBox1.setTitle("串口狀態(tài)(開啟)")
          # 定時(shí)器接收數(shù)據(jù) self.timer = QTimer() self.timer.timeout.connect(self.data_receive) # 打開串口接收定時(shí)器,周期為1ms self.timer.start(1)


          3.4、定時(shí)發(fā)送數(shù)據(jù)程序


          通過定時(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ù)值類型!')


          3.5、發(fā)送數(shù)據(jù)程序


          可以發(fā)送ASCII字符和十六進(jìn)制類型數(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ù),以空格分開!') return None
          input_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 += num self.Lineedit2.setText(str(self.data_num_sended)) else: pass


          3.6、接收數(shù)據(jù)程序


          可以接收ASCII字符和十六進(jìn)制類型數(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 None
          if 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 += num self.Lineedit3.setText(str(self.data_num_received)) else: pass


          3.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、打開博客、公眾號(hào)程序


          點(diǎn)擊按鈕,打開我的公眾號(hào)二維碼和博客主頁,實(shí)現(xiàn)代碼如下所示:


          # 打開博客鏈接和公眾號(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 = 0 self.Lineedit2.setText(str(self.data_num_sended))
          # 清除接收數(shù)據(jù)顯示 def receive_data_clear(self): self.Text1.setText("")
          self.data_num_received = 0 self.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
          # 切換開關(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 = 0 self.Lineedit2.setText(str(self.data_num_sended)) self.data_num_received = 0 self.Lineedit3.setText(str(self.data_num_received))
          self.formGroupBox1.setTitle("串口狀態(tài)(關(guān)閉)")


          往期推薦



          點(diǎn)擊閱讀原文,更精彩~
          瀏覽 60
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  caobi 国产 | 黄色在线免费网站 | 69av成人 | 国产黄色片在线播放 | 国产a片偷拍网站视频 |