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)
def update_tree_widgets(self, signals): self.signals_data = signals # 更新 Speed Tree # if “CCVS1” in signals: # self.mSpeedTreeWidget.topLevelItem(0).setText(3, f"{signals[‘CCVS1’]} km/h") # # # 更新 RPM Tree # if “EEC1_rpm” in signals: # self.mRPMTreeWidget.topLevelItem(0).setText(3, f"{signals[‘EEC1_rpm’]} rpm") # if “EEC1_torque” in signals: # self.mEECTreeWidget.topLevelItem(0).setText(3, f"{signals[‘EEC1_torque’]} %“) # # # 更新 VDHR (里程) # if “VDHR” in signals: # self.mVDHRTreeWidget.topLevelItem(0).setText(3, f”{signals[‘VDHR’]} km") # # # 更新 HOURS (工作时长) # if “HOURS” in signals: # self.mHoursTreeWidget.topLevelItem(0).setText(3, f"{signals[‘HOURS’]} hours") # # # 更新 LFE (平均油耗) # if “LFE” in signals: # self.mLFETreeWidget.topLevelItem(0).setText(3, f"{signals[‘LFE’]} L/100km") # # # 更新 ET1 (冷却液温度) # if “ET1” in signals: # self.mET1TreeWidget.topLevelItem(0).setText(3, f"{signals[‘ET1’]} °C") # # # 更新 AT1T1I (燃油液面) # if “AT1T1I” in signals: # self.mAT1T1ITreeWidget.topLevelItem(0).setText(3, f"{signals[‘AT1T1I’]} %") # # # 更新 ETC2 (档位) # if “ETC2” in signals: # self.mETC2TreeWidget.topLevelItem(0).setText(3, signals[‘ETC2’])
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文件
– 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 update_j1939_widgets(self, can_id, data): “”“根据 CAN ID 和原始数据更新对应的 J1939 显示控件”“” # 解析 CAN 帧 signals = parse_custom_can_frame(can_id, data) # 定义信号组与控件的映射关系 signal_group_map = { “CCVS1”: self.mSpeedTreeWidget, “EEC1_RPM”: self.mRPMTreeWidget, “VDHR”: self.mVDHRTreeWidget, “HOURS”: self.mHoursTreeWidget, “EEC1_Torque”: self.mEECTreeWidget, “ET1”: self.mET1TreeWidget, “AT1T1I”: self.mAT1T1ITreeWidget, “LFE”: self.mLFETreeWidget, “ETC2”: self.mETC2TreeWidget } # 遍历解析出的信号 for signal_name, signal_value in signals.items(): # 获取信号组前缀(例如 “CCVS1”) signal_group = signal_name.split('‘)[0] # 找到对应的 TreeWidget tree_widget = None for key, widget in signal_group_map.items(): if key.startswith(signal_group): tree_widget = widget break if not tree_widget: continue # 清除现有内容(可选,根据需要决定是否清除) tree_widget.clear() # 创建树节点 item = QtWidgets.QTreeWidgetItem(tree_widget) # 设置各列数据 item.setText(0, signal_name) # 信号名称 item.setText(1, f"0x{can_id:08X}“) # CAN ID (十六进制格式) # 格式化原始数据为十六进制字符串 if isinstance(data, bytes): hex_data = ’ '.join(f”{b:02X}" for b in data) else: hex_data = str(data) item.setText(2, hex_data) # 原始数据 # 显示信号值 item.setText(3, str(signal_value)) # 设置列宽自适应 for i in range(tree_widget.columnCount()): tree_widget.resizeColumnToContents(i) def parse_can_data(self, raw_data): “”“增强版CAN数据解析”“” try: # 尝试直接处理字节数据 if isinstance(raw_data, (bytes, bytearray)): return raw_data # 处理整数类型 if isinstance(raw_data, int): # 将整数转换为字节数组 length = (raw_data.bit_length() + 7) // 8 return raw_data.to_bytes(length, ‘big’) # 处理字符串类型 cleaned_str = str(raw_data).strip().upper() # 移除常见前缀 for prefix in [‘0X’, ‘\X’, ‘X’, ‘HEX:’]: if cleaned_str.startswith(prefix): cleaned_str = cleaned_str[len(prefix):] # 移除所有非十六进制字符 import re cleaned_str = re.sub(r’0-9A-F’, ‘’, cleaned_str) # 处理空字符串 if not cleaned_str: return b’’ # 处理奇数长度 if len(cleaned_str) % 2 != 0: cleaned_str = ‘0’ + cleaned_str # 高位补零 return bytes.fromhex(cleaned_str) except Exception as e: print(f"解析CAN数据错误: {raw_data} -> {e}“) return b’’ 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 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文件,现在程序存在一定问题,就是当can数据停止发送后,tab1界面仍然有较长时间在刷新数据,要求在can数据停止发送后,tab界面能够较快地(1s内)停止刷新,现在有一个思路是清除缓冲区文件,你认为应该怎么做?
最新发布