本人由于工作需要一个CAN的上位机,自学1个月,用的pyqt5+多线程。我在网上看到说是子线程中不能更新控件,但是实际上我通过重写QThread类,把mainwindow中的的tablewidget1和tablewidget2传进到QThread类中,发现可以更新控件也就没管了。后面出现了程序自动退出的问题,终端没有任何错误提示。于是我分别屏蔽了操作tablewidget1和tablewidget2的代码,发现只操作tablewidget1的话就不会自动退出了,不知道是哪点原因,下面是代码,请求各位技术大大们帮忙看看!
window.py:
# -*- coding: utf-8 -*-
# Form implementation generated from reading ui file '.\mainwindow.ui'
#
# Created by: PyQt5 UI code generator 5.15.4
#
# 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 *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
from canlib import canlib, kvadblib
import threading
import time
import display_widgets
import os
import sys
class CANThread(QtCore.QThread): #更新widget
def __init__(self,name,table_widget1,table_widget2,dbc,select_id):
super(CANThread, self).__init__()
self.name = name
self.Flag=True #停止标志位
self.table_widget1 = table_widget1 #分析窗口1
self.table_widget2 = table_widget2 #分析窗口2
self.dbc = dbc
self.db = None
self.select_id = select_id
self.ch = canlib.openChannel(channel=0,flags=canlib.Open.CAN_FD,bitrate=canlib.canFD_BITRATE_500K_80P,data_bitrate=canlib.canFD_BITRATE_2M_80P,)
self.ch.setBusOutputControl(canlib.canDRIVER_NORMAL)
def run(self):
while(True):
if(not self.Flag):
pass
else:
display_widgets.canfd_read(self.table_widget1,self.table_widget2,self.ch,self.dbc,self.db,self.select_id)
def setFlag(self,parm): #外部停止线程的操作函数
self.Flag=parm #boolean
def set_select_id(self,select_id):
self.select_id = select_id
def set_dbc(self,dbc):
self.dbc = dbc
def set_db(self,db):
self.db = db
class Ui_MainWindow(object):
def __init__(self):
self.start_flag = 0
def setupUi(self, MainWindow):
MainWindow.setObjectName("MainWindow")
MainWindow.resize(747, 634)
self.centralWidget = QtWidgets.QWidget(MainWindow)
self.centralWidget.setObjectName("centralWidget")
self.tableWidget = QtWidgets.QTableWidget(self.centralWidget)
self.tableWidget.setGeometry(QtCore.QRect(40, 10, 630, 341))
self.tableWidget.setObjectName("tableWidget")
self.tableWidget.setColumnCount(5)
self.tableWidget.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(1, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(2, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(3, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget.setHorizontalHeaderItem(4, item)
self.tableWidget_2 = QtWidgets.QTableWidget(self.centralWidget)
self.tableWidget_2.setGeometry(QtCore.QRect(40, 380, 500, 192))
self.tableWidget_2.setObjectName("tableWidget_2")
self.tableWidget_2.setColumnCount(2)
self.tableWidget_2.setRowCount(0)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_2.setHorizontalHeaderItem(0, item)
item = QtWidgets.QTableWidgetItem()
self.tableWidget_2.setHorizontalHeaderItem(1, item)
MainWindow.setCentralWidget(self.centralWidget)
self.menuBar = QtWidgets.QMenuBar(MainWindow)
self.menuBar.setGeometry(QtCore.QRect(0, 0, 747, 23))
self.menuBar.setObjectName("menuBar")
self.menu = QtWidgets.QMenu(self.menuBar)
self.menu.setObjectName("menu")
self.menu_2 = QtWidgets.QMenu(self.menuBar)
self.menu_2.setObjectName("menu_2")
self.menuDBC = QtWidgets.QMenu(self.menuBar)
self.menuDBC.setObjectName("menuDBC")
MainWindow.setMenuBar(self.menuBar)
self.statusBar = QtWidgets.QStatusBar(MainWindow)
self.statusBar.setObjectName("statusBar")
MainWindow.setStatusBar(self.statusBar)
self.actionopen = QtWidgets.QAction(MainWindow)
self.actionopen.setObjectName("actionopen")
self.actionclose = QtWidgets.QAction(MainWindow)
self.actionclose.setObjectName("actionclose")
self.actionstop = QtWidgets.QAction(MainWindow)
self.actionstop.setObjectName("actionstop")
self.actionrx = QtWidgets.QAction(MainWindow)
self.actionrx.setObjectName("actionrx")
self.actiontx = QtWidgets.QAction(MainWindow)
self.actiontx.setObjectName("actiontx")
self.actiondbcfile = QtWidgets.QAction(MainWindow)
self.actiondbcfile.setObjectName("actiondbcfile")
self.menu.addAction(self.actionopen)
self.menu.addAction(self.actionclose)
self.menu_2.addAction(self.actionrx)
self.menu_2.addAction(self.actiontx)
self.menu_2.addAction(self.actionstop)
self.menuDBC.addAction(self.actiondbcfile)
self.menuBar.addAction(self.menu.menuAction())
self.menuBar.addAction(self.menu_2.menuAction())
self.menuBar.addAction(self.menuDBC.menuAction())
self.retranslateUi(MainWindow)
QtCore.QMetaObject.connectSlotsByName(MainWindow)
def retranslateUi(self, MainWindow):
_translate = QtCore.QCoreApplication.translate
MainWindow.setWindowTitle(_translate("MainWindow", "CANFD_TOOL"))
item = self.tableWidget.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "时间"))
item = self.tableWidget.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "方向"))
item = self.tableWidget.horizontalHeaderItem(2)
item.setText(_translate("MainWindow", "ID"))
item = self.tableWidget.horizontalHeaderItem(3)
item.setText(_translate("MainWindow", "DLC"))
item = self.tableWidget.horizontalHeaderItem(4)
item.setText(_translate("MainWindow", "数据"))
item = self.tableWidget_2.horizontalHeaderItem(0)
item.setText(_translate("MainWindow", "信号"))
item = self.tableWidget_2.horizontalHeaderItem(1)
item.setText(_translate("MainWindow", "物理值"))
self.menu.setTitle(_translate("MainWindow", "设备"))
self.menu_2.setTitle(_translate("MainWindow", "数据"))
self.menuDBC.setTitle(_translate("MainWindow", "DBC"))
self.actionopen.setText(_translate("MainWindow", "打开"))
self.actionclose.setText(_translate("MainWindow", "关闭"))
self.actionstop.setText(_translate("MainWindow", "停止"))
self.actionrx.setText(_translate("MainWindow", "接受"))
self.actiontx.setText(_translate("MainWindow", "发送"))
self.actiondbcfile.setText(_translate("MainWindow", "路径"))
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget_2.horizontalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget_2.verticalHeader().setSectionResizeMode(QHeaderView.Stretch)
self.tableWidget.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.tableWidget_2.setEditTriggers(QAbstractItemView.NoEditTriggers)
self.actionopen.triggered.connect(self.open_onclick)
self.actionclose.triggered.connect(self.close_onclick)
self.actionrx.triggered.connect(self.rx_onclick)
self.actionstop.triggered.connect(self.stop_onclick)
self.actiondbcfile.triggered.connect(self.dbc_onclick)
self.tableWidget.doubleClicked.connect(self.double_onclick)
self.actionrx.setEnabled(0)
self.actiontx.setEnabled(0)
self.actionstop.setEnabled(0)
self.actionclose.setEnabled(0)
self.t1 = CANThread("table_widget",self.tableWidget,self.tableWidget_2,None,None)
self.t1.daemon = True
##self.t2.daemon = True
def open_onclick(self):
self.t1.ch.busOn()
self.actionrx.setEnabled(1)
self.actionopen.setEnabled(0)
self.actionclose.setEnabled(1)
def close_onclick(self):
self.start_flag = 1
self.t1.setFlag(False)
self.t1.ch.busOff()
self.actionrx.setEnabled(0)
self.actionopen.setEnabled(1)
self.actionclose.setEnabled(0)
def rx_onclick(self):
self.t1.setFlag(True)
self.actionrx.setEnabled(0)
self.actionstop.setEnabled(1)
if not self.start_flag:
self.t1.start()
self.tableWidget.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tableWidget.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tableWidget.horizontalHeader().setStretchLastSection(True)
self.tableWidget.verticalHeader().setStretchLastSection(True)
self.tableWidget_2.horizontalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tableWidget_2.horizontalHeader().setStretchLastSection(True)
self.tableWidget_2.verticalHeader().setSectionResizeMode(QHeaderView.ResizeToContents)
self.tableWidget_2.verticalHeader().setStretchLastSection(True)
def stop_onclick(self):
self.start_flag = 1
self.t1.setFlag(False)
self.actionrx.setEnabled(1)
self.actionstop.setEnabled(0)
def dbc_onclick(self):
filename, filetype = QFileDialog.getOpenFileName(self.centralWidget, "选择文件", "./","Dbc File(*.dbc)")
db = kvadblib.Dbc(filename=filename,protocol=9)
self.t1.set_db(db)
self.t1.set_dbc(filename)
def double_onclick(self):
self.t1.set_select_id(None)
self.tableWidget_2.clearContents()
self.tableWidget_2.setRowCount(0)
for i in self.tableWidget.selectedItems():
#print(i.row(), i.column(), i.text())
select_id = self.tableWidget.item(i.row(),2).text()
self.t1.set_select_id(select_id)
display_widgets.py:
from canlib import canlib, kvadblib
import time, datetime
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtWidgets import *
import time
import sys
def canfd_read(table_widget1,table_widget2,ch,dbc,db,select_id):
timeout = 1
frame = ch.read(timeout=int(timeout * 1000))
###print("id:", hex(frame.id))
###print("data:", bytes(frame.data))
###print("dlc:", frame.dlc)
###print("flags:", frame.flags)
canfd_data = []
for i in range(len(frame.data)):
canfd_data.append(str(hex(frame.data[i])))
timeStamp = float(frame.timestamp)/1000
ret_datetime = datetime.datetime.utcfromtimestamp(timeStamp).strftime("%H:%M:%S.%f")
items=table_widget1.findItems(str(hex(frame.id)),QtCore.Qt.MatchExactly)
if(items):
item = items[0]
iRow = item.row()
table_widget1.setItem(iRow,0,QTableWidgetItem(str(ret_datetime))) ### 时间
table_widget1.setItem(iRow,1,QTableWidgetItem("接受")) ### rx/tx
table_widget1.setItem(iRow,2,QTableWidgetItem(str(hex(frame.id)))) ### ID
table_widget1.setItem(iRow,3,QTableWidgetItem(str(frame.dlc))) ### DLC
table_widget1.setItem(iRow,4,QTableWidgetItem(str(canfd_data))) ### 数据
table_widget1.viewport().update()
else:
iRow = table_widget1.rowCount()
table_widget1.setRowCount(iRow + 1)
table_widget1.setItem(iRow,0,QTableWidgetItem(str(ret_datetime))) ### 时间
table_widget1.setItem(iRow,1,QTableWidgetItem("接受")) ### rx/tx
table_widget1.setItem(iRow,2,QTableWidgetItem(str(hex(frame.id)))) ### ID
table_widget1.setItem(iRow,3,QTableWidgetItem(str(frame.dlc))) ### DLC
table_widget1.setItem(iRow,4,QTableWidgetItem(str(canfd_data))) ### 数据
if(dbc == None) or (select_id == None) or (db == None) or (frame == None):
return
if str(hex(frame.id)) == select_id:
###db = kvadblib.Dbc(filename=dbc,protocol=9)
try:
bmsg = db.interpret(frame)
except:
print("<<< No message found for frame with id %s >>>" % frame.id)
return
for bsig in bmsg:
items=table_widget2.findItems(str(bsig.name),QtCore.Qt.MatchExactly)
if(items):
item = items[0]
iRow = item.row()
table_widget2.setItem(iRow,0,QTableWidgetItem(str(bsig.name)))
table_widget2.setItem(iRow,1,QTableWidgetItem(str(bsig.phys)+str(bsig.unit)))
table_widget2.viewport().update()
else:
iRow = table_widget2.rowCount()
table_widget2.setRowCount(iRow + 1)
table_widget2.setItem(iRow,0,QTableWidgetItem(str(bsig.name)))
table_widget2.setItem(iRow,1,QTableWidgetItem(str(bsig.phys)+str(bsig.unit)))
###db.close()
有可能是多个线程之间占用tablewidget导致的,如果单独执行tablewidget2也能成功,说明是资源抢夺问题,但tablewidget2无法运行,那就是这部代码有问题了