一、设计UI界面
使用qt设计师
需要注意的是
调整整体大小
最后设置整体自动调整大小时,对于QMainWindow窗口需要右键最基本的框,选择布局,不然在右侧是没有布局选项的
窗口放大时非对话框有最大大小,不跟着变大
设置对应窗口的对齐为 0
按钮进入对齐后选择minimum,可以变大
默认时
二、编写逻辑
编写基本框架
选择自己使用的是QMainWindow还是QWidget
导入pyside的库
- from PySide6.QtWidgets import QApplication,QMainWindow,QWidget
复制代码 引用对应界面库
- #ui为上一层目录
- from ui.Ui_serial_up import Ui_MainWindow
复制代码- class MyWindow(QMainWindow,Ui_MainWindow):
- def __init__(self):
- super().__init__()
- self.setupUi(self)
- if __name__ == "__main__":
- app = QApplication()
- window = MyWindow()
- window.show()
- sys.exit(app.exec())
复制代码 逻辑部分
导入串口所需库
- from PySide6.QtCore import QThread,Signal
- import serial
- import serial.tools.list_ports
复制代码 配置大体框架
- #接收线程
- class SerialReadThread(QThread):
- ReadSignal = Signal(str) #接收信号
- def __init__(self,serial_obj):
- super().__init__()
-
- def run():
-
- def stop():
复制代码 子窗口
子窗口现在qt设计师设计好,使用QSialog类型
- #子窗口界面
- class SettingSerial(QDialog,Ui_Dialog):
- def __init__(self,parent = None):#parent 为传入形参接口
- super().__init__(parent)
- self.setupUi(self)#调用子窗口Ui
- #绑定自带的确认和取消键
- #连接固定的确定取消方法
- #self.reject()和self.accept()是取消和确认方法
- self.buttonBox.accepted.connect(self.buttonAccept)
- self.buttonBox.rejected.connect(self.reject)
-
- def buttonAccept(self):
- self.accept()
- def backSetting(self):
- '''子窗口返回方法,同与父窗口调用后关闭子窗口时调用'''
复制代码 父窗口框架
- #界面
- class MyWindow(QMainWindow,Ui_MainWindow):
- def __init__(self):
- super().__init__()
- self.setupUi(self)#调用父窗口Ui
-
- def SerialSend(self):
-
- def SerialReceive(self):
-
- def SerialStart(self):
-
- def SerialStop(self):
-
- def ClearTx(self):
-
- def ClearRx(self):
-
复制代码 编写代码
首先编写主界面的基本操作- #清除
- def clearTx(self):
- self.TextEdit_2.clear()
-
- def clearRx(self):
- self.TextEdit_1.clear()
复制代码- #变量定义
- def initVariable(self):
- self.baudrate = "115200"
- self.bytesize = '8'
- self.stopbits_set = '1'
- self.parity_set = 'None'
- # 串口对象
- self.serial_port = None
- self.reader_thread = None
- self.send_byte_count = 0 #发送字节总数
- self.receive_byte_count = 0 #接收字节总数
复制代码- #按键关联方法
- def ConnectButton(self):
- #关联按键
- self.pushButton_5.clicked.connect(self.clearTx)
- self.pushButton.clicked.connect(self.clearRx)
- #打开串口
- self.pushButton_2.clicked.connect(self.SerialSwitch)
- #刷新端口
- self.action10.setShortcut('F5')
- self.action10.setStatusTip('刷新端口')
- self.action10.triggered.connect(self.RefreshSerial)
- #串口设置
- self.pushButton_4.clicked.connect(self.open_dialog)
- self.action20.setStatusTip('配置串口')
- self.action20.triggered.connect(self.open_dialog)
- #更改baud下拉栏
- self.comboBox_2.currentIndexChanged.
- connect(self.backBaudrate)
- #发送数据
- self.pushButton_3.clicked.connect(self.SendData)
复制代码 打开串口关闭串口
- def SerialSwitch(self):
- '''设置标志位,区分打开关闭串口'''
- if self.serial_port and self.serial_port.is_open:
- self.closeSerial()
- else:
- self.StartSerial()
- def StartSerial(self):
- #读取当前com口
- is_com = self.comboBox.currentText()
- if not is_com :
- QMessageBox.warning(self,"warning","没有可用的串口")
- return
- #读取的端口从 - 分割开
- com = is_com.split(" - ")[0]
- #把确认的端口信息赋值给局部变量,后面赋值给串口库形参
- baudrate = self.baudrate
- bytesize = int(self.bytesize)
- stopbits = serial.STOPBITS_ONE
- if self.stopbits_set == '1.5':
- stopbits = serial.STOPBITS_ONE_POINT_FIVE
- elif self.stopbits_set == '2':
- stopbits = serial.STOPBITS_TWO
- parity = serial.PARITY_NONE
- if self.parity_set == 'Odd':
- parity = serial.PARITY_ODD
- elif self.parity_set == 'Even':
- parity = serial.PARITY_EVEN
- elif self.parity_set == 'Mark':
- parity = serial.PARITY_MARK
- elif self.parity_set == 'Space':
- parity = serial.PARITY_SPACE
- try:
- self.serial_port = serial.Serial(
- port=com,
- baudrate=baudrate,
- bytesize=bytesize,
- stopbits=stopbits,
- parity=parity,
- timeout=0.1 # 读超时,让线程可以循环检查停止标志
- )
- except Exception as e:
- QMessageBox.critical(self, "错误", f"无法打开串口:{e}")
- return
- #开启多线程
- self.reader_thread = SerialReadThread(self.serial_port)
- #判断ReadSignal信号是否接收到数据,接收到进入数据处理
- self.reader_thread.ReadSignal.connect(self.on_data_received)
- self.reader_thread.start()
- #打开串口后将按钮改为关闭
- self.pushButton_2.setText('关闭串口')
- #失能部分按键,防止误触,出错
- self.set_serial_settings_enabled(False)
- def closeSerial(self):
- if self.reader_thread:
- self.reader_thread.stop()
- self.reader_thread = None
- if self.serial_port and self.serial_port.is_open:
- self.serial_port.close()
- self.serial_port = None
- self.pushButton_2.setText("打开串口")
- self.set_serial_settings_enabled(True)
复制代码 失能使能模块方法包装- def set_serial_settings_enabled(self, enabled):
- self.comboBox.setEnabled(enabled)
- self.comboBox_2.setEnabled(enabled)
- self.pushButton_4.setEnabled(enabled)
- self.action20.setEnabled(enabled)
复制代码
打开串口的时候,关闭其他使能
设置串口 读 多线程
- class SerialReadThread(QThread):
- #创建信号 , bytes类型
- ReadSignal = Signal(bytes)
- def __init__(self,serial_port):
- super().__init__()
- self.serial_port = serial_port
- self.is_running = False
- def run(self):
- self.is_running = True
- while self.is_running and self.serial_port and self.serial_port.is_open:
- try:
- #接收数据
- data = self.serial_port.read(self.serial_port.in_waiting or 1)
- if data:
- #将接收到的数据连接上信号
- self.ReadSignal.emit(data)
- except Exception as e:
- break
-
- def stop(self):
- self.is_running = False
- #等待主线程完成,使子线程完全退出
- self.wait()
复制代码 接收数据处理
- def on_data_received(self,data):
- #状态栏的变量,接收数据+1
- self.receive_byte_count += len(data)
- self.update_status_bar()
- #判断hex是否勾选
- if self.checkBox_3.isChecked():
- hex_str = data.hex().upper()
- hex_str = ' '.join(hex_str[i:i+2] for i in range(0, len(hex_str), 2))
- self.TextEdit_1.insertPlainText(hex_str + " ")
- else:
- try:
- text = data.decode('utf-8', errors='replace')
- except:
- text = str(data)
- self.TextEdit_1.insertPlainText(text)
- #自动滚动
- #返回光标
- cursor = self.TextEdit_1.textCursor()
- #光标移动到最后
- cursor.movePosition(cursor.MoveOperation.End)
- #页面到光标处
- self.TextEdit_1.setTextCursor(cursor)
复制代码 子窗口
子窗口
- class SettingSerial(QDialog,Ui_Dialog):
- def __init__(self,parent = None):
- super().__init__(parent)
- self.setupUi(self)
- self.buttonBox.accepted.connect(self.buttonAccept)
- self.buttonBox.rejected.connect(self.reject)
- #刷新子窗口com,父子一致
- def refreashCom(self,postList,currentPort):
- self.comboBox.clear()
- self.comboBox.addItems(postList)
- if currentPort :
- Index = self.comboBox.findText(currentPort)
- if Index>=0:
- self.comboBox.setCurrentIndex(Index)
- #刷新子窗口,父子一致
- def refreashBaud(self,baudrate):
- if baudrate :
- Index = self.comboBox_2.findText(baudrate)
- if Index>=0:
- self.comboBox_2.setCurrentIndex(Index)
- #刷新子窗口,父子一致
- def refreashother(self,bytesize,stopbits_set,parity_set):
- if bytesize :
- Index = self.comboBox_3.findText(bytesize)
- if Index>=0:
- self.comboBox_3.setCurrentIndex(Index)
- if stopbits_set :
- Index = self.comboBox_4.findText(stopbits_set)
- if Index>=0:
- self.comboBox_4.setCurrentIndex(Index)
- if parity_set :
- Index = self.comboBox_6.findText(parity_set)
- if Index>=0:
- self.comboBox_6.setCurrentIndex(Index)
-
- def buttonAccept(self):
- self.accept()
- def backSetting(self):
- com = self.comboBox.currentText()#.split(" - ")[0]
- return (com
- ,self.comboBox_2.currentText()
- ,self.comboBox_3.currentText()
- ,self.comboBox_4.currentText()
- ,self.comboBox_6.currentText()
- ,self.comboBox_5.currentText()
- )
复制代码 父窗口调用子窗口
父窗口按键关联
- def open_dialog(self):
- dialog = SettingSerial(self)
- '''刷新数据'''
- self.RefreshSerial()
- dialog.refreashCom(self.postList,self.currentPort)
- dialog.refreashBaud(self.baudrate)
- dialog.refreashother(self.bytesize,self.stopbits_set,self.parity_set)
- #使用.exec()方法,等待子窗口点击确认,此时可以返回一些数据
- if dialog.exec() == QDialog.Accepted:
- self.settings = dialog.backSetting()
- self.settingAccept(self.settings)
复制代码 返回数据- def settingAccept(self,settings):
- self.currentPort,self.baudrate,self.bytesize,self.stopbits_set,self.parity_set,flow_set = settings
- if self.currentPort :
- Index = self.comboBox.findText(self.currentPort)
- if Index>=0:
- self.comboBox.setCurrentIndex(Index)
- if self.baudrate :
- baud = self.comboBox_2.findText(self.baudrate)
- if baud>=0:
- self.comboBox_2.setCurrentIndex(baud)
复制代码 发送数据
- def SendData(self):
- if not self.serial_port or not self.serial_port.is_open:
- QMessageBox.warning(self, "警告", "请先打开串口!")
- return
- #读取当前发送框有什么
- text = self.TextEdit_2.toPlainText()
- if not text:
- return
- #判断是不是 使用hex方式
- if self.checkBox_3.isChecked():
- hex_str = ''.join(text.split())
- try:
- #.fromhex 转16进制
- data = bytes.fromhex(hex_str)
- except ValueError as e:
- QMessageBox.warning(self, "错误", f"无效的十六进制字符串:{e}")
- return
- else:
- #ASCII发送
- data = text.encode('utf-8', errors='ignore')
- try:
- #返回发送的长度
- sent_bytes = self.serial_port.write(data)
- #状态栏
- self.send_byte_count += sent_bytes
- self.update_status_bar()
- except Exception as e:
- QMessageBox.critical(self, "错误", f"发送失败:{e}")
复制代码 运行
- if __name__ == "__main__":
- app = QApplication()
- window = MyWindow()
- window.setWindowIcon(QIcon("icon.png"))
- window.show()
- sys.exit(app.exec())
复制代码 状态栏
可以创建QLabel窗口,然后使用.addPermanentWidget(self.label)一直添加到状态栏右侧- def status_bars(self):
- '''多状态栏'''
- status_text = f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节"
- self.serial_status_label = QLabel(status_text)
- self.statusBar.addPermanentWidget(self.serial_status_label)
- self.textlabel = QLabel(' 天天好心情')
- self.statusBar.addPermanentWidget(self.textlabel)
- def update_status_bar(self):
- """更新状态栏显示:发送/接收字节数"""
- # status_text = f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节"
- # self.statusBar.setStyleSheet("QStatusBar { padding-left: 1000px; }")
- # 设置状态栏文本(showMessage默认显示5秒,传0表示永久显示)
- # self.statusBar.showMessage(status_text, 0)
- self.serial_status_label.setText(f"接收:{self.receive_byte_count} 字节 | 发送:{self.send_byte_count} 字节")
复制代码 https://gitee.com/liliww/serial-upper-computer.git
来源:程序园用户自行投稿发布,如果侵权,请联系站长删除
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作! |