# -*- coding: utf-8 -*- """ Created on Mon May 27 14:31:38 2024 @author: WANGXIBAO """ import sys,os import serial,re import serial.tools.list_ports import time,datetime from PyQt5 import QtWidgets from PyQt5.Qt import QPainter from PyQt5.QtWidgets import QMessageBox ,QFileDialog,QInputDialog, QFrame from PyQt5.QtCore import QTimer from serial import Serial from PyUartUi import Ui_UartAssistant from UartDataPolt import QChartViewPlot,UpdateDataThread,GetDataTF from PyQt5.QtChart import QChartView from PyQt5.QtGui import QIcon from configparser import ConfigParser from BigData_Plot import ChartDialog class PyQt5Serial(QtWidgets.QWidget,Ui_UartAssistant): ser: Serial | Serial # %%初始化程序 def __init__(self): super(PyQt5Serial, self).__init__() self.setupUi(self) self.quick_num = 99 self.IniPath = "PyUart.ini" self.log_time = 10 self.log_buffer = {} #定义成一个字典,键--文件名,值--对于收到的字符串列表 self.qxCfg=() self.tfCfg=() self.otCfg=() self.current_lines = [] #定义一个空列表,存储待显示数据 self.update_data_thread = UpdateDataThread() # 创建更新波形数据线程 self.get_data_tf = GetDataTF() self.get_data_tf.IndOfReturn(0) #根据数据特点给一个初始值 self.chart_dialog = ChartDialog() self.init() self.CheckCfgIniData() #更改按钮的文字 self.ser = serial.Serial() #创建一个空对象 self.port_check() # 设置Logo和标题 self.setWindowIcon(QIcon('./favicon.ico')) self.setWindowTitle("调试助手") # 设置禁止拉伸窗口大小 #self.setFixedSize(self.width(), self.height()) # 发送数据和接收数据数目置零 self.data_num_sended = 0 self.lineEditSendNum.setText(str(self.data_num_sended)) self.data_num_received = 0 self.lineEditReceiveNum.setText(str(self.data_num_received)) # 串口关闭按钮使能关闭 self.pushButtonCloseSerial.setEnabled(False) # 发送框、文本框清除 self.textEditReceive.setPlainText("") self.textEditReceive.setMaximumBlockCount(5000) self.textEditSend.setText("") # %%第二个TAB 初始化画图页面表格 self.pushButtonStopPlot.setEnabled(False) self.pushButtonStartPlot.setEnabled(True) self.radioButtonCH4QX.setEnabled(True) self.radioButtonCH4TF.setEnabled(True) self.checkBoxAutoSaveCsv.setEnabled(False) self.pushButton_expend.setEnabled(False) # 加载Qchart波形界面 self.plot_qchart = QChartViewPlot() #设置外边框为0 self.plot_qchart.setBackgroundRoundness(0) self.plot_qchart.layout().setContentsMargins(0, 0, 0, 0) self.plot_view.setChart(self.plot_qchart) self.plot_view.setRenderHint(QPainter.Antialiasing) # 抗锯齿 self.plot_view.setRubberBand(QChartView.RectangleRubberBand) # 移除外部边框 # self.plot_view.setFrameShape(QFrame.NoFrame) # self.plot_view.setStyleSheet("border: none;") #加载快捷指令 self.widget_6.hide() #加载快捷指令的按键值 # 用于暂存接收的串口数据 self.buffer = b'' # 用于暂存解码数据 self.lineUtf8 = "" # 用于标志是否开始存CSV self.flag_draw = 0 #用于暂存大数据 self.bigdata=[] #开启大数据模式标志位 self.flag_bigdata =0 self.double_click_timers = {} # 存储双击定时器 # ============================================================================= # def wheelEvent(self, event): # if self.plot_view.underMouse: # # 鼠标滚轮:缩放Qchart波形 # if event.angleDelta().y() >= 0: # # 鼠标滚轮向上 # if event.x() < ( # self.plot_view.width() + self.plot_view.x()) and event.x() > self.plot_view.x(): # if event.y() < ( # self.plot_view.height() + self.plot_view.y()) and event.y() > self.plot_view.y(): # self.plot_qchart.zoomIn() # else: # # 鼠标滚轮向下 # if event.x() < ( # self.plot_view.width() + self.plot_view.x()) and event.x() > self.plot_view.x(): # if event.y() < ( # self.plot_view.height() + self.plot_view.y()) and event.y() > self.plot_view.y(): # self.plot_qchart.zoomOut() # ============================================================================= #%% 重写关闭按钮 def closeEvent(self, event): self.update_data_thread.stop() # 可选:加入超时判断,防止线程未能正常退出导致程序无法关闭 if not self.update_data_thread.wait(1000): # 等待5秒 print("线程未在指定时间内退出,可能需要进一步处理") # 如果串口已经打开,则关闭串口 if self.ser.is_open: self.port_close() #关闭界面前保存快捷区域的命令和名称 for i in range(self.quick_num): # 假设有20个按钮 index_str = f"{i:02}" # 确保编号为两位数字形式 lineEditName = f"lineEditQuick_{index_str}" buttonName = f"pushButtonQuick_{index_str}" # 格式化按钮名称,确保两位数 button_name = f"button{index_str}" set_text = getattr(self,lineEditName).text()+ "|" + getattr(self,buttonName).text() self.SetCfgIniData(button_name, set_text) # 调用父类的关闭事件处理函数 super().closeEvent(event) # %%建立控件信号与槽关系 def init(self): # 串口检测按钮 self.pushButtonTestSerial.clicked.connect(self.port_check) # 串口打开按钮 self.pushButtonOpenSerial.clicked.connect(self.port_open) # 串口关闭按钮 self.pushButtonCloseSerial.clicked.connect(self.port_close) # 定时发送数据 self.timer_send = QTimer() self.timer_send.timeout.connect(self.data_send) self.checkBoxReapitSend.stateChanged.connect(self.data_send_timer) # 发送数据按钮 self.pushButtonSend.clicked.connect(lambda:self.data_send(text_quick= None)) # 保存日志 self.pushButtonLogSave.clicked.connect(self.savefiles) # 加载日志 self.pushButtonLogLoad.clicked.connect(self.openfiles) # hexRecevie与savCsv的按键关联 self.checkBoxHexReceive.stateChanged.connect(self.hex_link_savCsv) # 清除发送按钮 self.pushButtonClearSend.clicked.connect(self.send_data_clear) # 清除接收按钮 self.pushButtonClearReceive.clicked.connect(self.receive_data_clear) # 开始绘图 self.pushButtonStartPlot.clicked.connect(self.btn_start_clicked) # 关闭绘图 self.pushButtonStopPlot.clicked.connect(self.btn_stop_clicked) #线程信号发射 self.update_data_thread._signal_update.connect(self.update_data_thread_slot) # 选择绘图 self.comboBoxPlot.currentIndexChanged.connect(self.plot_item_changed) # 重置绘图 self.pushButtonResetPlot.clicked.connect(self.plot_reset) # 快捷指令扩展区域 self.pushButton_expend.clicked.connect(self.adjust_sidebar) #大数据模式 self.pushButton_bigdata.clicked.connect(self.bigdata_show) # 创建一个通用的槽函数来处理所有按钮 # 动态创建控件并存储引用 for i in range(self.quick_num): # 从0到20 index_str = f"{i:02}" # 确保编号为两位数字形式 horizontalLayoutName = f"horizontalLayoutQuick_{index_str}" horizontalLayout = QtWidgets.QHBoxLayout() horizontalLayout.setObjectName(horizontalLayoutName) # 创建 QLineEdit 并设置动态属性 lineEditName = f"lineEditQuick_{index_str}" setattr(self, lineEditName, QtWidgets.QLineEdit(self.layoutWidget1)) getattr(self, lineEditName).setObjectName(lineEditName) horizontalLayout.addWidget(getattr(self, lineEditName)) # 创建 QPushButton 并设置动态属性 buttonName = f"pushButtonQuick_{index_str}" setattr(self, buttonName, QtWidgets.QPushButton(self.layoutWidget1)) getattr(self, buttonName).setObjectName(buttonName) horizontalLayout.addWidget(getattr(self, buttonName)) self.verticalLayout_8.addLayout(horizontalLayout) # 连接按钮点击事件到槽函数 button = getattr(self, buttonName) if button: button.clicked.connect(lambda checked, idx=i: self.onButtonClick(idx)) # %% 串口检测 def port_check(self): # 检测所有存在的串口,将信息存储在字典中 self.Com_Dict = {} port_list = list(serial.tools.list_ports.comports()) self.comboBoxSerial.clear() for port in port_list: self.Com_Dict["%s" % port[0]] = "%s" % port[1] self.comboBoxSerial.addItem(port[0]) # 无串口判断 if len(self.Com_Dict) == 0: self.comboBoxSerial.addItem("无串口") # %%打开串口 def port_open(self): self.ser.port = self.comboBoxSerial.currentText() # 串口号 self.ser.baudrate = int(self.comboBoxBaudrate.currentText()) # 波特率 self.ser.timeout = 0.001 flag_data = int(self.comboBoxDataBits.currentText()) # 数据位 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.comboBoxCheckBit.currentText() # 校验位 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.comboBoxStopBit.currentText()) # 停止位 if flag_data == 1: self.ser.stopbits = serial.STOPBITS_ONE else: self.ser.stopbits = serial.STOPBITS_TWO flag_data = self.comboBoxFlow.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.checkBoxDTR.isChecked(): self.ser.dsrdtr = True #硬件流控 DTR if self.checkBoxRTS.isChecked(): self.ser.rtscts = True #硬件流控 RTS try: time.sleep(0.1) if self.ser.is_open: self.ser.close() self.ser.open() except: QMessageBox.critical(self, "串口异常", "此串口不能被打开!") return None # 串口打开后,切换开关串口按钮使能状态,防止失误操作 if self.ser.isOpen(): self.pushButtonOpenSerial.setEnabled(False) self.pushButtonCloseSerial.setEnabled(True) self.comboBoxBaudrate.setEnabled(False) self.comboBoxSerial.setEnabled(False) self.pushButton_expend.setEnabled(True) #self.formGroupBox1.setTitle("串口状态(开启)") #日志保存 # 格式化日期时间字符串,用于文件名 # 例如:2024-05-28_12-34-56.txt self.file = self.ser.port+"-"+time.strftime("%Y%m%d%H%M%S", time.localtime()) self.filename = self.file + ".txt" # 定时器接收数据 self.timer = QTimer() self.timer.timeout.connect(self.data_receive) # 打开串口接收定时器,周期为1ms self.timer.start(20) # %%接收数据 def data_receive(self): try: num = self.ser.inWaiting() if num>0 : #print("接收数据",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) try: data = self.ser.read(num) except: QMessageBox.critical(self, '串口异常') self.buffer+=data #print("接收完成",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # 获取到text光标 textCursor = self.textEditReceive.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到text中去 self.textEditReceive.setTextCursor(textCursor) if self.checkBoxAddDate.isChecked(): nowTime = datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f") nowTime = nowTime[:-3] self.textEditReceive.insertPlainText(nowTime + " ") #self.add_line_to_textedit(nowTime + " ") # HEX显示数据 if self.checkBoxHexReceive.checkState(): out_s = '' for i in range(0, len(data)): out_s = out_s + '{:02X}'.format(data[i]) + ' ' self.textEditReceive.insertPlainText(out_s) #self.add_line_to_textedit(out_s) # ASCII显示数据 else: #print("解码前",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) self.textEditReceive.insertPlainText(data.decode('utf-8',errors='replace')) #self.add_line_to_textedit(data.decode('utf-8',errors='replace')) #print("解码数据",datetime.datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")) # 接收换行 if self.checkBoxCRLF.isChecked(): self.textEditReceive.insertPlainText('\r\n') #self.add_line_to_textedit('\r\n') # 统计接收字符的数量 self.data_num_received += num self.lineEditReceiveNum.setText(str(self.data_num_received)) # 自动保存日志 if self.checkBoxAutoSaveLog.isChecked(): self.AutoSaveLog() if self.flag_bigdata == 1: self.BigDataPlot() except: # QMessageBox.critical(self, '串口异常', '串口接收数据异常,请重新连接设备!') # 获取到text光标 textCursor = self.textEditReceive.textCursor() # 滚动到底部 textCursor.movePosition(textCursor.End) # 设置光标到text中去 self.textEditReceive.setTextCursor(textCursor) self.textEditReceive.insertPlainText("串口断开,重连中...\r\n") self.ser.close() try: print("重连中...") time.sleep(1) if not self.ser.is_open: self.ser.open() print("重连成功") self.textEditReceive.insertPlainText("重连成功\r\n") else: print("串口已连接,无需重连") except Exception as e: print(f"重连失败{e}") # %%定时发送数据 def data_send_timer(self): try: if 1<= int(self.lineEditTime.text()) <= 30000: # 定时时间1ms~30s内 if self.checkBoxReapitSend.isChecked(): self.timer_send.start(int(self.lineEditTime.text())) self.lineEditTime.setEnabled(False) else: self.timer_send.stop() self.lineEditTime.setEnabled(True) else: QMessageBox.critical(self, '定时发送数据异常', '定时发送数据周期仅可设置在30秒内!') except: QMessageBox.critical(self, '定时发送数据异常', '请设置正确的数值类型!') # %%发送数据 def data_send(self,text_quick = None): if self.ser.isOpen(): if text_quick== None: input_s = self.textEditSend.toPlainText() else: input_s = text_quick # 判断是否为非空字符串 if input_s != "": # 时间显示 if self.checkBoxAddDate.isChecked(): self.textEditReceive.insertPlainText((time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " ") # HEX发送 if self.checkBoxHexSend.isChecked(): input_s = input_s.strip() send_list = [] while input_s != '': try: num = int(input_s[0:2], 16) except ValueError: QMessageBox.critical(self, '串口异常', '请输入规范十六进制数据,以空格分开!') return None input_s = input_s[2:].strip() send_list.append(num) input_s = bytes(send_list) # ASCII发送 else: input_s = (input_s).encode('utf-8') input_s = re.sub(b'(?1: self.buffer = lines.pop() else: self.buffer = b'' # 处理每一行数据 for line in lines: # 注意:每行数据可能不包含结尾的换行符,所以在处理前检查一下 if line.endswith(b'\r'): line = line[:-1] # 移除回车 if self.checkBoxHexReceive.checkState(): lineUtf8 = line.hex() out_s = ' '.join(['{:02X}'.format(b) for b in bytes.fromhex(lineUtf8)]) saveData = datetime.datetime.now().strftime("%Y-%m-%dT%H:%M:%S.%f")[:23] +" " +out_s +"\r\n" else: lineUtf8 = line.decode('utf-8',errors='replace') saveData = (time.strftime("%Y-%m-%d %H:%M:%S", time.localtime())) + " " + lineUtf8 + "\r\n" # 将日志信息添加到缓冲区 if self.filename not in self.log_buffer: self.log_buffer[self.filename] = [] self.log_buffer[self.filename].append(saveData) # 当缓冲区中的记录达到10条时,写入文件 if len(self.log_buffer[self.filename]) >= self.log_time: with open(self.filename, mode='a', newline='',encoding='utf-8', errors='replace') as file: file.writelines(self.log_buffer[self.filename]) self.log_buffer[self.filename].clear() #判断选择的何种格式数据 if self.radioButtonCH4QX.isChecked(): self.get_data_tf.SetConfig(self.qxCfg) if self.radioButtonCH4TF.isChecked(): self.get_data_tf.SetConfig(self.tfCfg) if self.radioButtonOtherData.isChecked(): self.get_data_tf.SetConfig(self.otCfg) print(lineUtf8) if self.flag_draw: dataSplit = self.get_data_tf.Transdata(lineUtf8) #print("dataSplit",type(dataSplit)) if isinstance(dataSplit, (float, int)): self.filenameCsv= self.file + ".csv" if self.checkBoxAutoSaveCsv.isChecked(): #写入CSV文件 try: self.get_data_tf.SaveCsv(self.filenameCsv,self.log_time) except: print("写入CSV失败") pass self.update_data_thread.SetFlag(1) #print("dataSplit",dataSplit) self.update_data_thread.SetReceiveData(dataSplit) #更新当前数据 self.lineEditCurrentValue.setText(str(round(dataSplit,3))) self.lineEditWindowMean.setText (str(round(self.plot_qchart.windowAverage,3))) self.lineEditWindowMSE.setText (str(round(self.plot_qchart.windowStd,3))) else: print("Data split failed, dataSplit type:",type(dataSplit)) except Exception as e: print(f"Error reading configuration: {e}") print("自动保存日志失败") pass def BigDataPlot(self): try: lines = self.buffer.split(b'\n') # 或者使用 b'\r\n' 根据你的需要 # 最后一个元素可能不包含完整的行,所以将其保留作为新的缓存 self.buffer = lines.pop() # 处理每一行数据 for line in lines: # 注意:每行数据可能不包含结尾的换行符,所以在处理前检查一下 if line.endswith(b'\r'): line = line[:-1] # 移除回车 lineUtf8 = line.decode('utf-8') if "end" in lineUtf8.lower() or len(self.bigdata) > 4999: tansData = (range(len(self.bigdata)), self.bigdata) self.chart_dialog.tans_data(tansData) self.chart_dialog.draw_figure() self.bigdata = [] else: try: self.bigdata.append(float(lineUtf8)) # print(f'bigdata length:{len(self.bigdata)}') except: pass except: return None def send_data_clear(self): self.textEditSend.setText("") self.data_num_sended = 0 self.lineEditSendNum.setText(str(self.data_num_sended)) # 清除接收数据显示 def receive_data_clear(self): self.textEditReceive.setPlainText("") self.data_num_received = 0 self.lineEditSendNum.setText(str(self.data_num_received)) # 关联hex接收与保存csv,hex下不保存csv def hex_link_savCsv(self): if self.checkBoxHexReceive.isChecked(): self.checkBoxAutoSaveCsv.setChecked(False) else: self.checkBoxAutoSaveCsv.setChecked(True) #设置接受区域显示条数 def add_line_to_textedit(self, new_line): # 获取当前文本并按行分割 #current_lines = self.textEditReceive.toPlainText().splitlines() # 添加新的行到列表中 self.current_lines.append(new_line) # 如果行数超过100,则删除最早的行,直到剩下100行 if len(self.current_lines) > 100: self.current_lines = self.current_lines[-100:] # 只保留最新的100行 # 将更新后的行列表转换回字符串并设置为textEdit的内容 self.textEditReceive.setPlainText(''.join(self.current_lines)) #self.textEditReceive.setPlainText(self.current_lines) # 关闭串口 def port_close(self): try: self.timer.stop() self.timer_send.stop() self.btn_stop_clicked() #执行停止绘图操作 self.ser.close() except: QMessageBox.critical(self, '串口异常', '关闭串口失败,请重启程序!') return None # 切换开关串口按钮使能状态和定时发送使能状态 self.pushButtonOpenSerial.setEnabled(True) self.pushButtonCloseSerial.setEnabled(False) self.lineEditTime.setEnabled(True) self.comboBoxBaudrate.setEnabled(True) self.comboBoxSerial.setEnabled(True) self.pushButton_expend.setEnabled(False) # 发送数据和接收数据数目置零 self.data_num_sended = 0 self.lineEditSendNum.setText(str(self.data_num_sended)) self.data_num_received = 0 self.lineEditReceiveNum.setText(str(self.data_num_received)) #self.formGroupBox1.setTitle("串口状态(关闭)") #开始绘图 def btn_start_clicked(self): #开启按钮 self.update_data_thread.start() self.update_data_thread.restart() self.pushButtonStartPlot.setEnabled(False) self.pushButtonStopPlot.setEnabled(True) self.radioButtonCH4QX.setEnabled(False) self.radioButtonCH4TF.setEnabled(False) self.radioButtonOtherData.setEnabled(False) self.checkBoxAutoSaveCsv.setEnabled(True) iterm = self.get_data_tf.rowTitle[1:] print("iterm",iterm) self.comboBoxPlot.addItems(iterm) self.update_data_thread.SetPlotItem(0) self.update_data_thread.restart() self.flag_draw = 1 #停止绘图 def btn_stop_clicked(self): self.update_data_thread.stop() self.pushButtonStartPlot.setEnabled(True) self.pushButtonStopPlot.setEnabled(False) self.radioButtonCH4QX.setEnabled(True) self.radioButtonCH4TF.setEnabled(True) self.radioButtonOtherData.setEnabled(True) self.checkBoxAutoSaveCsv.setEnabled(False) self.comboBoxPlot.clear() self.flag_draw = 0 def update_data_thread_slot(self, data): # 线程回调函数 #data = json.loads(data) self.plot_qchart.handle_update(float(data)) #print("thread ",data) def plot_item_changed(self,index): print(index) self.plot_qchart.clearSeries() self.get_data_tf.IndOfReturn(index) def plot_reset(self): self.plot_qchart.zoomReset() #开关快捷指令栏 def adjust_sidebar(self): if self.widget_6.isHidden(): self.widget_6.show() else: self.widget_6.hide() def onPushButtonQuickClicked(self, line_edit): text = getattr(self, line_edit).text() #print(f"Button clicked: {text}") if self.checkBox_return.isChecked(): text = text + "\r\n" self.data_send(text) def CheckCfgIniData(self): if not os.path.exists(self.IniPath): config = ConfigParser() #数据处理正则表达 config.add_section('QX_config') config.set('QX_config', 'regular', '\+?-?\d+(?:\.\d+)?') config.set('QX_config', 'headStr', 'A+') config.set('QX_config', 'rowTitle', 'time,Methane,Air Temp,Laser Temp,Laser Intensity') config.add_section('TF_config') config.set('TF_config', 'regular', '\+?-?\d+(?:\.\d+)?') config.set('TF_config', 'headStr', 'A+') config.set('TF_config', 'rowTitle', 'time,Methane,Air Temp,Laser Temp,Laser Intensity,amplification,NL,ND,Sinal,SNR,PEAK,Best Piont') config.add_section('OtherData_config') config.set('OtherData_config', 'regular', '\+?-?\d+(?:\.\d+)?') # config.set('TF_config', 'regular', '(A\+|B\+|\s)+') config.set('OtherData_config', 'headStr', 'A+') config.set('OtherData_config', 'rowTitle', 'time,DATA1,DATA2') #按键配置 config.add_section('Quick_config') config.set('Quick_config', 'log_time', '10') for i in range(self.quick_num): idx = f'{i:02}' button_name = f'Button{idx}' # 格式化按钮名称,确保两位数 config.set('Quick_config', button_name, '') with open(self.IniPath, 'w' ,encoding='utf-8') as f: config.write(f) config = ConfigParser() config.read(self.IniPath, encoding='utf-8') try: # 创建一个空字典来存储按钮名称和对应的配置 self.log_time = int(config.get('Quick_config', 'log_time')) self.qxCfg = (config.get('QX_config','regular'),config.get('QX_config','headStr'),config.get('QX_config','rowTitle')) print('Quick_config:',self.qxCfg) self.tfCfg = (config.get('TF_config','regular'),config.get('TF_config','headStr'),config.get('TF_config','rowTitle')) print('TF_config:',self.tfCfg) self.otCfg = (config.get('OtherData_config','regular'),config.get('OtherData_config','headStr'),config.get('OtherData_config','rowTitle')) print('OtherData_config:',self.otCfg) # 循环遍历按钮编号,从0到19 for i in range(self.quick_num): idx = f'{i:02}' button_name = f'Button{idx}' # 格式化按钮名称,确保两位数 # 使用 get 方法安全地获取配置,如果不存在则返回空字符串 config_value = config.get('Quick_config', button_name, fallback='') config_value_split = config_value.split('|') # 将按钮名称和配置信息存储在字典中 if len(config_value_split) == 2: # 打印字典查看结果,并赋值 print(button_name,config_value_split[0],config_value_split[1]) getattr(self, f'pushButtonQuick_{idx}').setText(config_value_split[1]) getattr(self, f'lineEditQuick_{idx}').setText(config_value_split[0]) except Exception as e: print(f"Error reading configuration: {e}") def SetCfgIniData(self,button_name,set_text): config = ConfigParser() config.read(self.IniPath, encoding='utf-8') config.set('Quick_config', button_name, set_text) with open(self.IniPath, 'w' ,encoding='utf-8') as f: config.write(f) def onButtonClick(self, idx): # 槽函数处理按钮点击事件 if idx not in self.double_click_timers: self.double_click_timers[idx] = None if self.double_click_timers[idx] is None: self.double_click_timers[idx] = True QTimer.singleShot(200, lambda: self.onButtonSigleClick(idx)) else: self.onButtonDoubleClick(idx) def onButtonSigleClick(self, idx): index_str = f"{idx:02}" if self.double_click_timers[idx]: self.double_click_timers[idx] = None lineEdit = getattr(self, f"lineEditQuick_{index_str}") print(f"Text in lineEdit_{idx}: {lineEdit.text()}") text = lineEdit.text() if self.checkBox_return.isChecked(): text = text + "\r\n" self.data_send(text) def onButtonDoubleClick(self, idx): # 槽函数处理按钮双击事件 self.double_click_timers[idx] = None index_str = f"{idx:02}" print(f"Double click detected on Button {index_str}.") button = getattr(self, f"pushButtonQuick_{index_str}") new_name, ok = QInputDialog.getText(self, 'Button Rename', 'Enter new button name:') if ok and new_name: button.setText(new_name) def bigdata_show(self): if self.flag_bigdata == 0: self.chart_dialog.show() self.flag_bigdata = 1 self.checkBoxAutoSaveLog.setChecked(False) else: self.chart_dialog.close() self.flag_bigdata = 0 self.checkBoxAutoSaveLog.setChecked(True) #执行 if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) myshow = PyQt5Serial() myshow.show() sys.exit(app.exec_())