1.5.Qt.ui文件是怎么生成相应的.h文件

本文探讨了.ui文件如何通过uic命令自动生成对应的.ui头文件。.ui文件在编译过程中转换为.h文件,便于Qt应用程序中使用。
探究下.ui文件是怎么生成相应的.h文件的。.ui文件在编译文件时通过uic -o ui_***.h ***.ui 命令自动生成ui头文件。
import serial import time import struct from datetime import datetime CanOBDItemList = [[0, 0, 0, 0, 0]] Frame_start = b'\xFF' Frame_end = b'\x55' Frame_data_style_len = 6 Frame_Data_Len = 0 frame_buffer = bytearray() class CanInfShow_Item: def __int__(self, CanID, CanFramType, Len, CanDataInf): self.SystemCycle = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3], self.CanID = CanID, self.CanFrame = CanFramType, self.CanDataLen = Len, self.CanData = CanDataInf class SerialPort: def __init__(self, port, baudrate): # 初始化串口参数 self.port = port self.baudrate = baudrate self.ser = serial.Serial( port=self.port, baudrate=self.baudrate, bytesize=serial.EIGHTBITS, parity=serial.PARITY_NONE, stopbits=serial.STOPBITS_ONE, timeout=0.1 # 添加串口读取超时 ) # 添加超时检测机制 self.last_receive_time = time.time() # 记录最后接收时间 self.timeout_threshold = 1.5 # 超时阈值(秒) self.data_active = True # 初始状态为活跃 self.timeout_counter = 0 # 超时计数器 self.max_timeout_count = 3 # 连续超时3次后判定为停止 self.frame_count = 0 # 帧计数器 self.last_frame_count = 0 # 上次帧计数 # 等待串口连接稳定 time.sleep(0.2) if not self.ser.isOpen(): print("串口打开失败!") def close(self): # 关闭串口连接 if self.ser.isOpen(): self.ser.close() def send(self, data): # 发送数据 if self.ser.isOpen(): try: self.ser.write(data.encode('utf-8')) except serial.SerialException as e: print(f"发送数据失败: {e}") def recv(self): # 接收数据 - 使用非阻塞读取 if self.ser.isOpen(): try: # 读取所有可用数据,最多1024字节 data = self.ser.read(min(1024, self.ser.in_waiting)) return data except serial.SerialException as e: print(f"接收数据错误: {e}") return b'' def __del__(self): self.close() def SerialIsOpen(self): return 1 if self.ser.isOpen() else 0 def Frame_check_sum(self, data, length): """计算校验和""" checksum = 0 for i in range(length): checksum += data[i] return checksum % 0x100 # 检查数据超时状态 def check_data_timeout(self): """检查数据接收是否超时并更新状态""" current_time = time.time() elapsed = current_time - self.last_receive_time # 检查帧计数是否变化 if self.frame_count == self.last_frame_count: # 帧计数未变化,更新超时计数器 if elapsed > self.timeout_threshold: self.timeout_counter += 1 else: # 有新帧,重置计数器和时间 self.timeout_counter = 0 self.last_frame_count = self.frame_count self.last_receive_time = current_time # 连续超时达到阈值 if self.timeout_counter >= self.max_timeout_count: if self.data_active: print(f"数据接收超时({elapsed:.2f}s),停止界面更新") self.data_active = False return True # 数据活跃状态 if not self.data_active and self.timeout_counter == 0: print("检测到数据流,开始更新界面") self.data_active = True return False # 发送数据并接收响应 def Com_read_frame(self): global frame_buffer global Frame_Data_Len # 检查超时状态 if self.check_data_timeout(): # 超时状态下不处理数据 return byte_data = self.recv() if byte_data: # 更新最后接收时间 self.last_receive_time = time.time() frame_buffer.extend(byte_data) # 添加缓冲区大小限制(1MB) if len(frame_buffer) > 1024 * 1024: # 保留最后512KB frame_buffer = frame_buffer[-512 * 1024:] # 如果没有足够数据,提前返回 if len(frame_buffer) < Frame_data_style_len: return # 查找帧起始和结束位置 start_index = frame_buffer.find(Frame_start) end_index = frame_buffer.find(Frame_end) # 如果找不到起始帧或结束帧 if start_index == -1 or end_index == -1: # 清除无效数据(保留最后几个字节) if len(frame_buffer) > 10: frame_buffer = frame_buffer[-10:] return # 处理帧起始和结束位置关系 if start_index + 1 == end_index: # 计算帧长度 if start_index + 3 >= len(frame_buffer): return # 数据不足 Frame_Data_Len = (frame_buffer[start_index + 3] << 8) | frame_buffer[start_index + 2] # 调整缓冲区,使起始位置在0 frame_buffer = frame_buffer[start_index:] start_index = 0 elif end_index < start_index: # 结束标志在起始标志前,调整缓冲区 frame_buffer = frame_buffer[start_index:] start_index = 0 # 重新查找结束位置 end_index = frame_buffer.find(Frame_end) # 检查是否有完整帧 if len(frame_buffer) >= Frame_Data_Len + 5: # 计算校验和 data_start = start_index + 2 data_end = data_start + Frame_Data_Len + 2 if data_end > len(frame_buffer): return # 数据不足 checksum = self.Frame_check_sum(frame_buffer[data_start:data_end], Frame_Data_Len + 2) expected_checksum = frame_buffer[start_index + Frame_Data_Len + 4] if checksum == expected_checksum: # 提取完整帧 frame_end_pos = start_index + Frame_Data_Len + 5 frame_procee = frame_buffer[start_index:frame_end_pos] # 处理帧数据 self.Frame_analoy_process(frame_procee) self.frame_count += 1 # 增加帧计数 # 更新缓冲区 if len(frame_buffer) == frame_end_pos: frame_buffer.clear() else: frame_buffer = frame_buffer[frame_end_pos:] Frame_Data_Len = 0 else: # 校验失败,跳过这一帧 skip_pos = start_index + Frame_Data_Len + 6 if skip_pos < len(frame_buffer): frame_buffer = frame_buffer[skip_pos:] else: frame_buffer.clear() Frame_Data_Len = 0 # 报文解析 def Frame_analoy_process(self, Framedata): # 检查数据活跃状态 if not self.data_active: return # 数据超时状态下不更新界面 # 检查帧类型 (0x0C 0x98) if len(Framedata) < 8 or Framedata[4] != 0x0C or Framedata[5] != 0x98: return try: FrameNum = int(Framedata[7]) except IndexError: return # 检查是否有足够数据 if len(Framedata) < 12 * FrameNum + 8: return for index in range(FrameNum): # 时间戳 Cantime = datetime.now().strftime("%Y-%m-%d %H:%M:%S.%f")[:-3] # 提取ID字节 try: id_bytes = [ Framedata[12 * index + 11], # LSB Framedata[12 * index + 10], Framedata[12 * index + 9], Framedata[12 * index + 8] # MSB ] except IndexError: continue # 格式化为8位大写十六进制 CanID = ''.join(format(b, '02X') for b in id_bytes) CanFramType = "Cycle" Len = 8 # 提取数据部分 try: CanDataSpace = ' '.join( format(Framedata[12 * index + 12 + posindex], '02X') for posindex in range(8) ) except IndexError: continue CanItemData = [Cantime, CanID, CanFramType, Len, CanDataSpace] # 更新列表 if not CanOBDItemList or CanOBDItemList[0][0] == 0: if CanOBDItemList and CanOBDItemList[0][0] == 0: CanOBDItemList.pop(0) CanOBDItemList.insert(0, CanItemData) else: Listpos = self.find_in_2d_list(CanOBDItemList, CanID) if Listpos is not None: CanOBDItemList[Listpos[0]] = CanItemData else: CanOBDItemList.append(CanItemData) def find_in_2d_list(self, matrix, target): """在二维列表中查找目标""" for i, row in enumerate(matrix): if target in row: return (i, row.index(target)) return None 这是serialpro的代码 # -*- coding: utf-8 -*- import threading # Form implementation generated from reading ui file 'CanOBD.ui' # # Created by: PyQt5 UI code generator 5.15.9 # # WARNING: Any manual changes made to this file will be lost when pyuic5 is # run again. Do not edit this file unless you know what you are doing. from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtCore import QThread, pyqtSignal,QTimer from PyQt5.QtWidgets import QApplication, QTableWidget, QTableWidgetItem from SerialPro import SerialPort as SerialThread from SerialPro import CanOBDItemList from can_parser import parse_custom_can_frame import time import serial import serial.tools.list_ports class Ui_MainWindow(object): def setupUi(self, MainWindow): MainWindow.setObjectName("MainWindow") MainWindow.resize(1220, 940) font = QtGui.QFont() font.setPointSize(12) MainWindow.setFont(font) self.centralwidget = QtWidgets.QWidget(MainWindow) self.centralwidget.setObjectName("centralwidget") self.tabWidget = QtWidgets.QTabWidget(self.centralwidget) self.tabWidget.setGeometry(QtCore.QRect(0, 0, 1041, 940)) self.tabWidget.setObjectName("tabWidget") self.tab = QtWidgets.QWidget() self.tab.setObjectName("tab") self.tableWidget = QtWidgets.QTableWidget(self.tab) self.tableWidget.setGeometry(QtCore.QRect(0, 0, 1031, 940)) self.tableWidget.setObjectName("tableWidget") self.tableWidget.setColumnCount(5) self.tableWidget.setRowCount(150) for num in range(0,150,1): item = QtWidgets.QTableWidgetItem() self.tableWidget.setVerticalHeaderItem(num, item) item = QtWidgets.QTableWidgetItem() font = QtGui.QFont() font.setKerning(False) item.setFont(font) for line in range(0,5,1): self.tableWidget.setHorizontalHeaderItem(line, item) item = QtWidgets.QTableWidgetItem() self.tabWidget.addTab(self.tab, "") self.tab_2 = QtWidgets.QWidget() self.tab_2.setObjectName("CanOBD Cfg Set") self.mSpeedTreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mSpeedTreeWidget.setGeometry(QtCore.QRect(10, 0, 1031, 101)) self.mSpeedTreeWidget.setObjectName("mSpeedTreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mSpeedTreeWidget.headerItem().setFont(0, font) self.mSpeedTreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mSpeedTreeWidget.headerItem().setFont(3, font) self.mRPMTreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mRPMTreeWidget.setGeometry(QtCore.QRect(10, 100, 1031, 91)) self.mRPMTreeWidget.setObjectName("mRPMTreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mRPMTreeWidget.headerItem().setFont(0, font) self.mRPMTreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mRPMTreeWidget.headerItem().setFont(3, font) self.mVDHRTreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mVDHRTreeWidget.setGeometry(QtCore.QRect(10, 190, 1031, 91)) self.mVDHRTreeWidget.setObjectName("mVDHRTreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mVDHRTreeWidget.headerItem().setFont(0, font) self.mVDHRTreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mVDHRTreeWidget.headerItem().setFont(3, font) self.mHoursTreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mHoursTreeWidget.setGeometry(QtCore.QRect(10, 280, 1031, 101)) self.mHoursTreeWidget.setObjectName("mHoursTreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mHoursTreeWidget.headerItem().setFont(0, font) self.mHoursTreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mHoursTreeWidget.headerItem().setFont(3, font) self.mEECTreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mEECTreeWidget.setGeometry(QtCore.QRect(10, 380, 1031, 91)) self.mEECTreeWidget.setObjectName("mEECTreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mEECTreeWidget.headerItem().setFont(0, font) self.mEECTreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mEECTreeWidget.headerItem().setFont(3, font) self.mET1TreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mET1TreeWidget.setGeometry(QtCore.QRect(10, 470, 1031, 101)) self.mET1TreeWidget.setObjectName("mET1TreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mET1TreeWidget.headerItem().setFont(0, font) self.mET1TreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mET1TreeWidget.headerItem().setFont(3, font) self.mAT1T1ITreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mAT1T1ITreeWidget.setGeometry(QtCore.QRect(10, 570, 1031, 91)) self.mAT1T1ITreeWidget.setObjectName("mAT1T1ITreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mAT1T1ITreeWidget.headerItem().setFont(0, font) self.mAT1T1ITreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mAT1T1ITreeWidget.headerItem().setFont(3, font) self.mLFETreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mLFETreeWidget.setGeometry(QtCore.QRect(10, 660, 1031, 101)) self.mLFETreeWidget.setObjectName("mLFETreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mLFETreeWidget.headerItem().setFont(0, font) self.mLFETreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mLFETreeWidget.headerItem().setFont(3, font) self.mETC2TreeWidget = QtWidgets.QTreeWidget(self.tab_2) self.mETC2TreeWidget.setGeometry(QtCore.QRect(10, 760, 1031, 101)) self.mETC2TreeWidget.setObjectName("mETC2TreeWidget") font = QtGui.QFont() font.setPointSize(12) self.mETC2TreeWidget.headerItem().setFont(0, font) self.mETC2TreeWidget.headerItem().setTextAlignment(1, QtCore.Qt.AlignJustify|QtCore.Qt.AlignVCenter) font = QtGui.QFont() font.setKerning(True) self.mETC2TreeWidget.headerItem().setFont(3, font) self.tabWidget.addTab(self.tab_2, "") self.mComCfgBox = QtWidgets.QGroupBox(self.centralwidget) self.mComCfgBox.setGeometry(QtCore.QRect(1040, 10, 191, 231)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mComCfgBox.setFont(font) self.mComCfgBox.setObjectName("mComCfgBox") self.mPortName = QtWidgets.QLabel(self.mComCfgBox) self.mPortName.setGeometry(QtCore.QRect(20, 30, 61, 21)) self.mPortName.setObjectName("mPortName") self.mBpsName = QtWidgets.QLabel(self.mComCfgBox) self.mBpsName.setGeometry(QtCore.QRect(20, 60, 61, 21)) self.mBpsName.setObjectName("mBpsName") self.mDatabitName = QtWidgets.QLabel(self.mComCfgBox) self.mDatabitName.setGeometry(QtCore.QRect(20, 90, 61, 21)) self.mDatabitName.setObjectName("mDatabitName") self.mStopName = QtWidgets.QLabel(self.mComCfgBox) self.mStopName.setGeometry(QtCore.QRect(20, 120, 61, 21)) self.mStopName.setObjectName("mStopName") self.mOddName = QtWidgets.QLabel(self.mComCfgBox) self.mOddName.setGeometry(QtCore.QRect(20, 150, 61, 21)) self.mOddName.setObjectName("mOddName") self.mDatabitVal = QtWidgets.QLabel(self.mComCfgBox) self.mDatabitVal.setGeometry(QtCore.QRect(100, 90, 54, 21)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mDatabitVal.setFont(font) self.mDatabitVal.setLayoutDirection(QtCore.Qt.LeftToRight) self.mDatabitVal.setAlignment(QtCore.Qt.AlignCenter) self.mDatabitVal.setObjectName("mDatabitVal") self.mStopBitVal = QtWidgets.QLabel(self.mComCfgBox) self.mStopBitVal.setGeometry(QtCore.QRect(100, 120, 54, 21)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mStopBitVal.setFont(font) self.mStopBitVal.setLayoutDirection(QtCore.Qt.LeftToRight) self.mStopBitVal.setAlignment(QtCore.Qt.AlignCenter) self.mStopBitVal.setObjectName("mStopBitVal") self.mOddVal = QtWidgets.QLabel(self.mComCfgBox) self.mOddVal.setGeometry(QtCore.QRect(100, 150, 54, 21)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mOddVal.setFont(font) self.mOddVal.setLayoutDirection(QtCore.Qt.LeftToRight) self.mOddVal.setAlignment(QtCore.Qt.AlignCenter) self.mOddVal.setObjectName("mOddVal") self.mPortVal = QtWidgets.QComboBox(self.mComCfgBox) self.mPortVal.setGeometry(QtCore.QRect(90, 30, 81, 22)) self.mPortVal.setObjectName("mPortVal") self.mPortVal.addItem("") self.mPortVal.addItem("") self.mPortVal.addItem("") self.mPortVal.addItem("") self.mPortVal.addItem("") self.mPortVal.addItem("") self.mBPSVal = QtWidgets.QComboBox(self.mComCfgBox) self.mBPSVal.setGeometry(QtCore.QRect(90, 60, 81, 22)) self.mBPSVal.setObjectName("mBPSVal") self.mBPSVal.addItem("") self.mBPSVal.addItem("") self.mBPSVal.addItem("") self.mBPSVal.addItem("") self.mBPSVal.addItem("") self.mBPSVal.addItem("") self.mOpenSerial = QtWidgets.QDialogButtonBox(self.mComCfgBox) self.mOpenSerial.setGeometry(QtCore.QRect(20, 190, 156, 31)) self.mOpenSerial.setStandardButtons(QtWidgets.QDialogButtonBox.Close|QtWidgets.QDialogButtonBox.Open) self.mOpenSerial.setObjectName("mOpenSerial") self.mCycleCfgBox = QtWidgets.QGroupBox(self.centralwidget) self.mCycleCfgBox.setGeometry(QtCore.QRect(1040, 260, 191, 221)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mCycleCfgBox.setFont(font) self.mCycleCfgBox.setObjectName("mCycleCfgBox") self.mcheck1000ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck1000ms.setGeometry(QtCore.QRect(20, 180, 141, 31)) self.mcheck1000ms.setObjectName("mcheck1000ms") self.mcheck500ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck500ms.setGeometry(QtCore.QRect(20, 150, 141, 31)) self.mcheck500ms.setObjectName("mcheck500ms") self.mcheck100ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck100ms.setGeometry(QtCore.QRect(20, 90, 141, 31)) self.mcheck100ms.setObjectName("mcheck100ms") self.mcheck50ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck50ms.setGeometry(QtCore.QRect(20, 60, 141, 31)) self.mcheck50ms.setObjectName("mcheck50ms") self.mcheck20ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck20ms.setGeometry(QtCore.QRect(20, 30, 141, 31)) self.mcheck20ms.setObjectName("mcheck20ms") self.mcheck200ms = QtWidgets.QCheckBox(self.mCycleCfgBox) self.mcheck200ms.setGeometry(QtCore.QRect(20, 120, 141, 31)) self.mcheck200ms.setObjectName("mcheck200ms") self.mEventSigBox = QtWidgets.QGroupBox(self.centralwidget) self.mEventSigBox.setGeometry(QtCore.QRect(1050, 490, 191, 151)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mEventSigBox.setFont(font) self.mEventSigBox.setObjectName("mEventSigBox") self.radioLeftREvent = QtWidgets.QRadioButton(self.mEventSigBox) self.radioLeftREvent.setGeometry(QtCore.QRect(10, 30, 151, 16)) self.radioLeftREvent.setObjectName("radioLeftREvent") self.radioKiilEvent = QtWidgets.QRadioButton(self.mEventSigBox) self.radioKiilEvent.setGeometry(QtCore.QRect(10, 90, 151, 16)) self.radioKiilEvent.setObjectName("radioKiilEvent") self.radioPEvent = QtWidgets.QRadioButton(self.mEventSigBox) self.radioPEvent.setGeometry(QtCore.QRect(10, 120, 151, 16)) self.radioPEvent.setObjectName("radioPEvent") self.radioOpenCloseEvent = QtWidgets.QRadioButton(self.mEventSigBox) self.radioOpenCloseEvent.setGeometry(QtCore.QRect(10, 60, 151, 16)) self.radioOpenCloseEvent.setObjectName("radioOpenCloseEvent") self.mReadOBDinfBox = QtWidgets.QGroupBox(self.centralwidget) self.mReadOBDinfBox.setGeometry(QtCore.QRect(1050, 660, 191, 171)) font = QtGui.QFont() font.setPointSize(14) font.setBold(True) font.setWeight(75) self.mReadOBDinfBox.setFont(font) self.mReadOBDinfBox.setObjectName("mReadOBDinfBox") self.radioVinRead = QtWidgets.QRadioButton(self.mReadOBDinfBox) self.radioVinRead.setGeometry(QtCore.QRect(10, 40, 141, 21)) self.radioVinRead.setObjectName("radioVinRead") self.mVinInfShow = QtWidgets.QTextBrowser(self.mReadOBDinfBox) self.mVinInfShow.setGeometry(QtCore.QRect(10, 70, 171, 91)) self.mVinInfShow.setObjectName("mVinInfShow") MainWindow.setCentralWidget(self.centralwidget) self.statusbar = QtWidgets.QStatusBar(MainWindow) self.statusbar.setObjectName("statusbar") MainWindow.setStatusBar(self.statusbar) self.retranslateUi(MainWindow) self.tabWidget.setCurrentIndex(0) QtCore.QMetaObject.connectSlotsByName(MainWindow) def retranslateUi(self, MainWindow): _translate = QtCore.QCoreApplication.translate MainWindow.setWindowTitle(_translate("MainWindow", "MainWindow")) for num in range(0, 150, 1): item = self.tableWidget.verticalHeaderItem(num) item.setText(_translate("MainWindow", str(num +1))) item = self.tableWidget.horizontalHeaderItem(0) item.setText(_translate("MainWindow", "时间标识")) item = self.tableWidget.horizontalHeaderItem(1) item.setText(_translate("MainWindow", "帧ID")) item = self.tableWidget.horizontalHeaderItem(2) item.setText(_translate("MainWindow", "帧类型")) item = self.tableWidget.horizontalHeaderItem(3) item.setText(_translate("MainWindow", "长度")) item = self.tableWidget.horizontalHeaderItem(4) item.setText(_translate("MainWindow", "数据 (BIT7--BIT0 大端模式)")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "Tab 1")) self.mSpeedTreeWidget.headerItem().setText(0, _translate("MainWindow", "速度[CCVS1]")) self.mSpeedTreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mSpeedTreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mSpeedTreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(km/h)")) self.mSpeedTreeWidget.setColumnWidth(0, 150) self.mSpeedTreeWidget.setColumnWidth(1, 150) self.mSpeedTreeWidget.setColumnWidth(2,550) self.mSpeedTreeWidget.setColumnWidth(3, 150) self.mRPMTreeWidget.headerItem().setText(0, _translate("MainWindow", "速[EEC1]")) self.mRPMTreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mRPMTreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mRPMTreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(rpm)")) self.mRPMTreeWidget.setColumnWidth(0, 150) self.mRPMTreeWidget.setColumnWidth(1, 150) self.mRPMTreeWidget.setColumnWidth(2,550) self.mRPMTreeWidget.setColumnWidth(3, 150) self.mVDHRTreeWidget.headerItem().setText(0, _translate("MainWindow", "里程[VDHR]")) self.mVDHRTreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mVDHRTreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mVDHRTreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(km)")) self.mVDHRTreeWidget.setColumnWidth(0, 150) self.mVDHRTreeWidget.setColumnWidth(1, 150) self.mVDHRTreeWidget.setColumnWidth(2,550) self.mVDHRTreeWidget.setColumnWidth(3, 150) self.mHoursTreeWidget.headerItem().setText(0, _translate("MainWindow", "工作时长[HOURS]")) self.mHoursTreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mHoursTreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mHoursTreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(hours)")) self.mHoursTreeWidget.setColumnWidth(0, 150) self.mHoursTreeWidget.setColumnWidth(1, 150) self.mHoursTreeWidget.setColumnWidth(2,550) self.mHoursTreeWidget.setColumnWidth(3, 150) self.mEECTreeWidget.headerItem().setText(0, _translate("MainWindow", "发动机负载[EEC1]")) self.mEECTreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mEECTreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mEECTreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(%)")) self.mEECTreeWidget.setColumnWidth(0, 150) self.mEECTreeWidget.setColumnWidth(1, 150) self.mEECTreeWidget.setColumnWidth(2,550) self.mEECTreeWidget.setColumnWidth(3, 150) self.mET1TreeWidget.headerItem().setText(0, _translate("MainWindow", "冷却液温度[ET1]")) self.mET1TreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mET1TreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mET1TreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(°)")) self.mET1TreeWidget.setColumnWidth(0, 150) self.mET1TreeWidget.setColumnWidth(1, 150) self.mET1TreeWidget.setColumnWidth(2,550) self.mET1TreeWidget.setColumnWidth(3, 150) self.mAT1T1ITreeWidget.headerItem().setText(0, _translate("MainWindow", "燃油液面[AT1T1I]")) self.mAT1T1ITreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mAT1T1ITreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mAT1T1ITreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(%)")) self.mAT1T1ITreeWidget.setColumnWidth(0, 150) self.mAT1T1ITreeWidget.setColumnWidth(1, 150) self.mAT1T1ITreeWidget.setColumnWidth(2,550) self.mAT1T1ITreeWidget.setColumnWidth(3, 150) self.mLFETreeWidget.headerItem().setText(0, _translate("MainWindow", "平均油耗[LFE]")) self.mLFETreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mLFETreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mLFETreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal(L/h)")) self.mLFETreeWidget.setColumnWidth(0, 150) self.mLFETreeWidget.setColumnWidth(1, 150) self.mLFETreeWidget.setColumnWidth(2,550) self.mLFETreeWidget.setColumnWidth(3, 150) self.mETC2TreeWidget.headerItem().setText(0, _translate("MainWindow", "档位[ETC2]")) self.mETC2TreeWidget.headerItem().setText(1, _translate("MainWindow", "CanID")) self.mETC2TreeWidget.headerItem().setText(2, _translate("MainWindow", "Data")) self.mETC2TreeWidget.headerItem().setText(3, _translate("MainWindow", "Signal")) self.mETC2TreeWidget.setColumnWidth(0, 150) self.mETC2TreeWidget.setColumnWidth(1, 150) self.mETC2TreeWidget.setColumnWidth(2,550) self.mETC2TreeWidget.setColumnWidth(3, 150) self.tableWidget.setColumnWidth(0, 200) self.tableWidget.setColumnWidth(1, 150) self.tableWidget.setColumnWidth(4,450) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab), _translate("MainWindow", "CanOBD Inf Show")) self.tabWidget.setTabText(self.tabWidget.indexOf(self.tab_2), _translate("MainWindow", "CanOBD J1939 Show")) self.mComCfgBox.setTitle(_translate("MainWindow", "串口配置")) self.mPortName.setText(_translate("MainWindow", "端口号")) self.mBpsName.setText(_translate("MainWindow", "波特率")) self.mDatabitName.setText(_translate("MainWindow", "数据位")) self.mStopName.setText(_translate("MainWindow", "停止位")) self.mOddName.setText(_translate("MainWindow", "检验位")) self.mDatabitVal.setText(_translate("MainWindow", "8")) self.mStopBitVal.setText(_translate("MainWindow", "1")) self.mOddVal.setText(_translate("MainWindow", "无")) self.mBPSVal.setItemText(0, _translate("MainWindow", "9600")) self.mBPSVal.setItemText(1, _translate("MainWindow", "19200")) self.mBPSVal.setItemText(2, _translate("MainWindow", "115200")) self.mBPSVal.setItemText(3, _translate("MainWindow", "230400")) self.mBPSVal.setItemText(4, _translate("MainWindow", "256000")) self.mBPSVal.setItemText(5, _translate("MainWindow", "460800")) port_list = list(serial.tools.list_ports.comports()) if port_list.__len__() is not 0: for num in range(port_list.__len__()): self.mPortVal.setItemText(num, _translate("MainWindow", str(port_list[num].device))) serialport = self.mPortVal.currentText() serialbaudrate = self.mBPSVal.currentText() self.LSerial = SerialThread(serialport, serialbaudrate) self.mCycleCfgBox.setTitle(_translate("MainWindow", "过滤设置(周期)")) self.mcheck1000ms.setText(_translate("MainWindow", "1000ms 周期")) self.mcheck500ms.setText(_translate("MainWindow", "500ms 周期")) self.mcheck100ms.setText(_translate("MainWindow", "100ms 周期")) self.mcheck50ms.setText(_translate("MainWindow", "50ms 周期")) self.mcheck20ms.setText(_translate("MainWindow", "20ms 周期")) self.mcheck200ms.setText(_translate("MainWindow", "200ms 周期")) self.mEventSigBox.setTitle(_translate("MainWindow", "事件信号策略")) self.radioLeftREvent.setText(_translate("MainWindow", "左右 事件")) self.radioKiilEvent.setText(_translate("MainWindow", "刹车 事件")) self.radioPEvent.setText(_translate("MainWindow", "档位 事件")) self.radioOpenCloseEvent.setText(_translate("MainWindow", "开关门 事件")) self.mReadOBDinfBox.setTitle(_translate("MainWindow", "主动读取信息")) self.radioVinRead.setText(_translate("MainWindow", "VIN 信息")) def OpenSerial(self): if self.LSerial != None: if self.LSerial.SerialIsOpen(): self.LSerial.__del__() port_list = list(serial.tools.list_ports.comports()) if port_list.__len__() != 0: serialport = self.mPortVal.currentText() serialbaudrate = self.mBPSVal.currentText() self.LSerial.__init__(serialport,serialbaudrate) # 开启线程 self.thread = Worker() # 创建线程对象 self.thread.update_signal.connect(self.CanOBDdatarefresh) # 连接信号和槽 self.thread.update_signal.connect(self.LSerial.Com_read_frame) # 连接信号和槽 self.thread.start() # 启动线程 #self.LSerial.Com_read_frame() def CloseSerial(self): if self.LSerial.SerialIsOpen(): self.LSerial.close() def Serialconnectslot(self): self.mOpenSerial.accepted.connect(self.OpenSerial) self.mOpenSerial.rejected.connect(self.CloseSerial) def CanOBDdatarefresh(self): index = 0 for indexitem in CanOBDItemList: itemTime = QTableWidgetItem(str(indexitem[0])) itemCanID = QTableWidgetItem(str(indexitem[1])) itemType = QTableWidgetItem(str(indexitem[2])) itemLen = QTableWidgetItem(str(indexitem[3])) itemData = QTableWidgetItem(str(indexitem[4])) self.tableWidget.setItem(index,0,itemTime) self.tableWidget.setItem(index, 1, itemCanID) self.tableWidget.setItem(index, 2, itemType) self.tableWidget.setItem(index, 3, itemLen) self.tableWidget.setItem(index, 4, itemData) # 新增:更新 J1939 显示 # try: # # 确保 CAN ID 是整数 # can_id = int(indexitem[1], 16) if isinstance(indexitem[1], str) else indexitem[1] # data = self.parse_can_data(item[4]) # 使用安全解析方法 # # self.update_j1939_widgets(can_id, data) # except Exception as e: # print(f"Error updating J1939 widgets: {e}") index += 1 #CanOBDItemList.clear() self.tableWidget.show() class Worker(QThread): update_signal = pyqtSignal(int) # 定义一个信号,用于传递更新信息到主线程 def run(self): # 模拟耗时操作 while True: time.sleep(0.001) self.update_signal.emit(1) # 发射信号,传递更新信息 这是canobd的代码 import sys sys.path.append('/UI/Login') from PyQt5 import QtCore, QtGui, QtWidgets from PyQt5.QtWidgets import QApplication, QWidget #from PyQt5.QtCore import QThread, pyqtSignal,QTimer from Login import Ui_Form as Login_ui from CanOBD import Ui_MainWindow as CanOBD_ui from PyQt5.QtWidgets import QMessageBox import time #import threading class LogInViewUI(QtWidgets.QWidget,Login_ui): def __int__(self): super(LogInViewUI,self).__int__() self.setupUi(self) def connectslot(self): #self.m_loginbuttonOn.clicked.connect(self.login_button) self.mloginButton.clicked.connect(self.login_button) def login_button(self): if self.mPassWordEdit.acceptRichText() == "": QMessageBox.warning(self, '警告', '密码不能为空,请输入!') return None # 1打开新窗口 CanOBDWidget.show() # 2关闭本窗口 LoginWidget.close() class CanOBDViewUI(QtWidgets.QWidget,CanOBD_ui): def __int__(self): super(CanOBDViewUI,self).__int__() self.setupUi(self) if __name__ == "__main__": app = QtWidgets.QApplication(sys.argv) #MainWidget = QtWidgets.QDockWidget() LoginWidget = QtWidgets.QWidget() CanOBDWidget = QtWidgets.QMainWindow() loginui = LogInViewUI() CanOBDui = CanOBDViewUI() loginui.setupUi(LoginWidget) loginui.connectslot() CanOBDui.setupUi(CanOBDWidget) CanOBDui.Serialconnectslot() LoginWidget.show() sys.exit(app.exec_()) 这是main的代码 现在这个程序存在一个问题,就是当can数据停止发送后,tab界面仍然有较长的时间还在持续刷新,我希望它在can数据停止发送之后,能够较快地停止刷新界面,在这个程序中有做过相关尝试的痕迹,但是效果不是很理想,你有什么想法吗?
最新发布
07-11
<think>问题分析: 在提供的代码中,`SerialPort`类中有一个`check_data_timeout`方法用于检测数据超时。它通过比较当前时间和最后接收时间,以及帧计数是否变化来判断是否超时。当连续超时达到一定次数(`max_timeout_count`)时,将`data_active`设置为False,从而停止更新界面。 然而,从描述来看,这个机制的效果不理想,即当CAN数据停止发送后,界面刷新并没有很快停止。 可能的原因: 1. 超时阈值(`timeout_threshold`)设置过长(1.5秒),导致检测到超时的时间较长。 2. 连续超时次数(`max_timeout_count`)设置为3次,意味着需要4.5秒(1.5秒*3)才能判定超时。 3. `check_data_timeout`方法在`Com_read_frame`中被调用,而`Com_read_frame`是在工作线程中通过信号触发的,触发频率为1ms一次(`time.sleep(0.001)`)。但是,在`Com_read_frame`中,如果没有接收到数据,就会很快返回,不会更新最后接收时间。因此,超时检测的频率很高,但判定超时的时间取决于阈值和连续超时次数。 改进建议: 1. 调整超时参数:将`timeout_threshold`减小(例如0.5秒),并将`max_timeout_count`减小(例如2次),这样总超时时间可以缩短到1秒。 2. 在`Com_read_frame`中,即使没有接收到数据,也会调用`check_data_timeout`,因此超时检测是实时的。但是,由于工作线程每1ms就触发一次,这可能会对性能造成影响。我们可以考虑在超时后降低检测频率,但这不是主要问题。 另外,在`CanOBDdatarefresh`方法中,刷新界面时并没有检查`data_active`状态。因此,即使`data_active`为False,界面仍然会刷新。我们需要在刷新界面之前检查`data_active`状态。 具体修改步骤: 1. 在`SerialPort`类中,调整超时参数: - 将`timeout_threshold`改为0.5(秒) - 将`max_timeout_count`改为2(次) 2. 在`SerialPort`类中,提供一个方法用于获取`data_active`的状态,例如: ```python def is_data_active(self): return self.data_active ``` 3. 在`Ui_MainWindow`的`CanOBDdatarefresh`方法中,在刷新界面之前检查串口对象的数据活跃状态: ```python def CanOBDdatarefresh(self): # 如果数据不活跃,则不刷新 if not self.LSerial.is_data_active(): return # 原有的刷新代码... ``` 4. 同时,在`SerialPort`的`check_data_timeout`方法中,当检测到数据重新活跃时,需要重置超时计数器并更新状态。这部分代码已经存在,但为了确保正确,我们检查一下逻辑。 5. 另外,在`Com_read_frame`方法中,当接收到数据时,会更新`last_receive_time`和`frame_count`。在`check_data_timeout`中,通过比较`frame_count`和`last_frame_count`来判断是否有新帧。但是,在`Com_read_frame`中,如果接收到数据但不足以构成一帧,`frame_count`不会增加,这可能导致超时检测误判。因此,我们应该在接收到任何数据时(即使不构成一帧)都更新`last_receive_time`,而不仅仅是在成功解析一帧后。 在现有代码中,`Com_read_frame`方法在接收到非空数据时就会更新`last_receive_time`: ```python byte_data = self.recv() if byte_data: # 更新最后接收时间 self.last_receive_time = time.time() frame_buffer.extend(byte_data) ``` 这是正确的,因为只要有数据到达,就说明连接是活跃的。 6. 但是,在`Frame_analoy_process`方法中,我们只处理特定类型的帧(0x0C 0x98),其他帧会被忽略。如果设备发送的是其他类型的帧,那么`frame_count`不会增加,但数据实际上在传输。这可能导致超时检测误判。因此,我们应该调整超时检测的逻辑:只要有数据到达(无论是否构成有效帧),就认为数据活跃。 目前,只要有数据到达,就会更新`last_receive_time`,而`check_data_timeout`中除了检查时间还检查帧计数。为了简化,我们可以只根据`last_receive_time`来判断数据活跃性,而不依赖帧计数。因为即使帧计数没有变化,只要有数据到达,就说明设备还在发送数据(可能是不完整的帧或无效帧)。 因此,修改`check_data_timeout`方法,去掉帧计数的检查,只根据时间差来判断: ```python def check_data_timeout(self): current_time = time.time() elapsed = current_time - self.last_receive_time # 如果超过阈值,则增加超时计数器 if elapsed > self.timeout_threshold: self.timeout_counter += 1 else: # 在超时阈值内,重置超时计数器 self.timeout_counter = 0 # 连续超时达到阈值 if self.timeout_counter >= self.max_timeout_count: if self.data_active: print(f"数据接收超时({elapsed:.2f}s),停止界面更新") self.data_active = False return True # 如果之前数据不活跃,但现在有数据到达(超时计数器为0),则重新激活 if not self.data_active and self.timeout_counter == 0: print("检测到数据流,开始更新界面") self.data_active = True return False ``` 这样,只要在超时阈值内收到任何数据,就会重置超时计数器,从而保持活跃状态。 7. 同时,我们不再需要`frame_count`和`last_frame_count`,可以移除这些变量。 修改后的`SerialPort`类中与超时相关的部分: ```python class SerialPort: def __init__(self, port, baudrate): # ... 其他初始化 self.last_receive_time = time.time() self.timeout_threshold = 0.5 # 超时阈值(秒) 改为0.5秒 self.data_active = True self.timeout_counter = 0 self.max_timeout_count = 2 # 连续超时2次后判定为停止 def check_data_timeout(self): current_time = time.time() elapsed = current_time - self.last_receive_time if elapsed > self.timeout_threshold: self.timeout_counter += 1 else: self.timeout_counter = 0 # 在阈值内有数据到达,重置计数器 if self.timeout_counter >= self.max_timeout_count: if self.data_active: print("数据接收超时,停止界面更新") self.data_active = False return True if not self.data_active and self.timeout_counter == 0: print("检测到数据流,开始更新界面") self.data_active = True return False ``` 8. 在`Ui_MainWindow`的`CanOBDdatarefresh`方法中,我们根据`data_active`状态来决定是否刷新界面。 9. 注意:在`SerialPort`类中,需要添加一个方法`is_data_active`供外部获取状态。 10. 另外,在`Com_read_frame`中,我们仍然会调用`check_data_timeout`,这样每次读取数据时都会检查超时。 11. 由于工作线程每1ms就触发一次刷新,即使没有数据,也会调用`CanOBDdatarefresh`,但此时因为`data_active`为False,所以不会进行刷新操作,从而减少界面刷新的开销。 修改后,当数据停止发送超过1秒(0.5秒*2)后,界面刷新就会停止。 代码修改示例: 在`SerialPort`类中修改`__init__`和`check_data_timeout`方法,并添加`is_data_active`方法。 在`Ui_MainWindow`的`CanOBDdatarefresh`方法开始处添加判断。 由于代码较长,这里只给出修改的关键部分。 修改`SerialPort`类(在SerialPro.py中): ```python class SerialPort: def __init__(self, port, baudrate): # ... 原有代码 # 修改超时参数 self.last_receive_time = time.time() # 记录最后接收时间 self.timeout_threshold = 0.5 # 超时阈值(秒),改为0.5秒 self.data_active = True # 初始状态为活跃 self.timeout_counter = 0 # 超时计数器 self.max_timeout_count = 2 # 连续超时2次后判定为停止 # 移除frame_count和last_frame_count # 修改check_data_timeout方法 def check_data_timeout(self): """检查数据接收是否超时并更新状态""" current_time = time.time() elapsed = current_time - self.last_receive_time # 检查是否超过阈值 if elapsed > self.timeout_threshold: self.timeout_counter += 1 else: # 在阈值内有数据到达(通过last_receive_time更新),重置计数器 self.timeout_counter = 0 # 连续超时达到阈值 if self.timeout_counter >= self.max_timeout_count: if self.data_active: print(f"数据接收超时({elapsed:.2f}s),停止界面更新") self.data_active = False return True # 如果之前是不活跃状态,但现在没有超时(timeout_counter为0),则重新激活 if not self.data_active and self.timeout_counter == 0: print("检测到数据流,开始更新界面") self.data_active = True return False # 添加一个方法获取data_active状态 def is_data_active(self): return self.data_active ``` 在`Ui_MainWindow`(CanOBD.py中)的`CanOBDdatarefresh`方法开始处添加: ```python def CanOBDdatarefresh(self): # 检查数据活跃状态,如果不活跃则直接返回 if not hasattr(self, 'LSerial') or not self.LSerial.is_data_active(): return # 原有的刷新代码... ``` 注意:在`Ui_MainWindow`中,`LSerial`可能尚未初始化(比如在第一次打开串口前)。因此,我们使用`hasattr`检查`LSerial`是否存在,然后检查其`is_data_active`状态。 12. 另外,在`SerialPort`的`recv`方法中,如果串口没有打开,我们返回空字节。在`Com_read_frame`中,如果接收到空字节,则不会更新`last_receive_time`,这样就会触发超时检测。 13. 最后,确保在串口关闭时,将`data_active`设置为False,并重置相关状态。 在`SerialPort`的`close`方法中: ```python def close(self): if self.ser.isOpen(): self.ser.close() self.data_active = False # 关闭串口时,数据不活跃 ``` 这样,当用户关闭串口时,界面刷新也会停止。 通过以上修改,应该能够较快地在CAN数据停止发送后停止界面刷新。 由于代码分散在多个文件中,请根据上述说明修改相应部分。 如果问题仍然存在,可能需要进一步调试超时检测逻辑。 注意:工作线程中每1ms就触发一次刷新和串口读取,频率较高,可能会对性能造成影响。如果界面刷新和串口读取操作耗时较长,可以考虑适当降低工作线程的触发频率(例如改为10ms或50ms)。 修改工作线程的休眠时间(在CanOBD.py的Worker类中): ```python def run(self): while True: time.sleep(0.01) # 改为10ms一次 self.update_signal.emit(1) ``` 这样可以减少CPU占用。 请根据实际情况调整。 由于修改涉及多个文件,请仔细检查。 如果修改后效果还不理想,可以进一步缩短超时阈值(比如0.2秒)和减少连续超时次数(比如1次),这样总超时时间就是0.2秒或0.4秒(取决于连续超时次数)。 但要注意,如果阈值设置过短,可能会因为数据包间隔正常波动而导致误判。 建议根据实际数据发送间隔来设置超时阈值,例如,如果数据包最大间隔为200ms,那么阈值可以设置为300ms。 根据问题描述,希望尽快停止刷新,所以可以尝试设置较小的阈值(如0.2秒)和1次连续超时。 请根据实际情况调整参数。</think>### 问题分析 在您的代码中,当CAN数据停止发送后界面仍在持续刷新的问题,主要是由于以下几个原因: 1. **超时检测机制不够敏感**: - 当前代码设置1.5秒的超时阈值和3次连续超时判定 - 这导致需要4.5秒才能检测到数据停止 2. **界面刷新与数据接收解耦不足**: - `CanOBDdatarefresh`方法直接访问全局变量`CanOBDItemList` - 即使没有新数据,界面也会刷新已有数据 3. **线程调度频率过高**: - 工作线程每1ms发送一次刷新信号 - 高频刷新导致界面持续更新 ### 解决方案 #### 1. 优化超时检测机制 修改`SerialPort`类中的超时检测逻辑: ```python class SerialPort: def __init__(self, port, baudrate): # ...其他初始化... self.timeout_threshold = 0.3 # 降低超时阈值到300ms self.max_timeout_count = 2 # 减少连续超时次数为2次 def check_data_timeout(self): current_time = time.time() elapsed = current_time - self.last_receive_time # 使用更敏感的检测逻辑 if elapsed > self.timeout_threshold: self.timeout_counter += 1 else: self.timeout_counter = 0 # 重置计数器 # 连续超时达到阈值 if self.timeout_counter >= self.max_timeout_count: if self.data_active: print(f"数据接收超时({elapsed:.2f}s),停止界面更新") self.data_active = False return True # 数据重新活跃 if not self.data_active and self.timeout_counter == 0: print("检测到数据流,开始更新界面") self.data_active = True return False ``` #### 2. 修改界面刷新逻辑 在`CanOBDdatarefresh`方法中添加数据活跃状态检查: ```python def CanOBDdatarefresh(self): # 检查数据活跃状态 if not self.LSerial.is_data_active(): return # 数据超时状态下不更新界面 # 原有的刷新代码... ``` 在`SerialPort`类中添加状态获取方法: ```python def is_data_active(self): return self.data_active ``` #### 3. 优化线程调度频率 降低刷新频率至更合理的水平: ```python class Worker(QThread): update_signal = pyqtSignal(int) def run(self): while True: time.sleep(0.05) # 降低刷新频率到20Hz self.update_signal.emit(1) ``` #### 4. 添加数据变化检测 在`Frame_analoy_process`方法中添加数据变化标志: ```python class SerialPort: def __init__(self, port, baudrate): # ...其他初始化... self.data_changed = False # 新增数据变化标志 def Frame_analoy_process(self, Framedata): # ...原有处理代码... # 设置数据变化标志 self.data_changed = True ``` 在`CanOBDdatarefresh`方法中检查数据变化: ```python def CanOBDdatarefresh(self): # 检查数据是否变化 if not self.LSerial.data_changed: return # 重置变化标志 self.LSerial.data_changed = False # 原有的刷新代码... ``` ### 完整修改方案 将上述修改整合到代码中: 1. 在`SerialPort`类中添加: ```python def is_data_active(self): return self.data_active @property def data_changed(self): return self._data_changed @data_changed.setter def data_changed(self, value): self._data_changed = value ``` 2. 在`Ui_MainWindow.CanOBDdatarefresh`中添加数据状态检查: ```python def CanOBDdatarefresh(self): # 检查数据活跃状态和变化状态 if not self.LSerial.is_data_active() or not self.LSerial.data_changed: return # 重置变化标志 self.LSerial.data_changed = False # 原有的刷新代码... ``` 3. 在`Frame_analoy_process`中设置数据变化标志: ```python def Frame_analoy_process(self, Framedata): # ...原有处理代码... self.data_changed = True # 设置数据变化标志 ``` ### 相关问题
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值