2025-02-13 08:29:55 +08:00

858 lines
35 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# -*- 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'(?<!\r)\n', b'\r\n', input_s)
# HEX接收显示
if self.checkBoxHexReceive.isChecked():
out_s = ''
for i in range(0, len(input_s)):
out_s = out_s + '{:02X}'.format(input_s[i]) + ' '
self.textEditReceive.insertPlainText(out_s)
# ASCII接收显示
else:
self.textEditReceive.insertPlainText(input_s.decode('utf-8',errors='replace'))
# 接收换行
if self.checkBoxCRLF.isChecked():
self.textEditReceive.insertPlainText('\r\n')
# 获取到Text光标
textCursor = self.textEditReceive.textCursor()
# 滚动到底部
textCursor.movePosition(textCursor.End)
# 设置光标到Text中去
self.textEditReceive.setTextCursor(textCursor)
# 统计发送字符数量
num = self.ser.write(input_s)
self.data_num_sended += num
self.lineEditSendNum.setText(str(self.data_num_sended))
else:
pass
# %%保存日志
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.textEditReceive.toPlainText())
except:
QMessageBox.critical(self, '日志异常', '保存日志文件失败!')
#%% 加载日志
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.textEditSend.setPlainText(file.read())
except:
QMessageBox.critical(self, '日志异常', '加载日志文件失败!')
# %%打开博客链接和公众号二维码
#webbrowser.open('https://blog.csdn.net/m0_38106923')
# %%清除发送数据显示
# 自动保存日志 log he csv
def AutoSaveLog(self):
try:
lines = self.buffer.split(b'\n') # 或者使用 b'\r\n' 根据你的需要
# 最后一个元素可能不包含完整的行,所以将其保留作为新的缓存
if len(lines)>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接收与保存csvhex下不保存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_())