pyqt5 写一个发送报文并在主页上显示的小程序

做一个简单的小程序,发送报文并在屏幕上显示。目前遇到的问题就是发送的报文无法在屏幕上显示出来,代码如下:

from __future__ import print_function
import can
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *
import time
import sys
import random
class MainWidget(QWidget):

    sinOut1=pyqtSignal(str)  #信号之文件路径
    def __init__(self,parent=None):
        super(MainWidget,self).__init__(parent)
        self.setWindowTitle("报文发送")
        self.resize(1400,600)  #调整窗口大小
        self.thread_tx = WORKER_tx()  #定义发送报文线程
        self.mesbox=QTextEdit()  #报文显示栏
        self.textline=QLineEdit()  #文件地址显示栏
        self.btnOpen = QPushButton("打开文件")
        self.btnflash = QPushButton("发送文件")
        self.btnRecv = QPushButton("接收文件")
        layout= QGridLayout(self)
        layout.addWidget(self.mesbox,0,0,5,2)
        layout.addWidget(self.textline,5,0)
        layout.addWidget(self.btnOpen,5,1)
        layout.addWidget(self.btnflash,6,0,1,2)
        layout.addWidget(self.btnRecv, 7, 0, 1, 2)
        self.btnOpen.clicked.connect(self.getfile)
        self.sinOut1.connect(self.show_filename)
        self.btnflash.clicked.connect(self.slot_start_tx)
        self.thread_tx.sinOut2.connect(self.data_flash) #定义信号与槽连接
    def getfile(self):  #打开文件,获得文件路径
        fname,_=QFileDialog.getOpenFileName(self,'Open File','.',"Hex File(*.hex *.Hex)")
        self.sinOut1.emit(str(fname))

    def show_filename(self,file_name): #显示文件路径
        self.textline.setText(file_name)

    def slot_start_tx(self):  # 发送报文线程
        self.btnflash.setEnabled(False)
        self.thread_tx.start()
    def data_flash(self,mes):
        self.mesbox.append(mes)

class WORKER_tx(QThread):  # 定义线程发送数据
    sinOut2 = pyqtSignal(str)

    def __init__(self, parent=None):
        super(WORKER_tx, self).__init__(parent)
        self.working = True
        '''定义发送报文通道'''
        self.bus_tx = can.interface.Bus(bustype='bmcan', channel=0, bitrate=500000, data_bitrate=2000000, tres=True)
        '''定义接收报文通道'''
        self.bus_rx = can.interface.Bus(bustype='bmcan', channel=1, bitrate=500000, data_bitrate=2000000, tres=True)

    def run(self):
        while self.working == True:
            data = [random.randint(0, 15) for i in range(0, 8)]
            msg = can.Message(arbitration_id=0xc0ffee,data=data,is_extended_id=True)
            self.bus_tx.send(msg)
            time.sleep(1)
            self.sinOut2.emit(str(self.bus_rx.recv()))  #发送报文信号
            # self.sinOut2.emit(str(msg))
        self.working = False

if __name__ == '__main__':
    app = QApplication(sys.argv)
    demo= MainWidget()
    demo.show()
    sys.exit(app.exec_())

用到了Python-can, can-tools, pyqt5等模块。
我这里有一个CAN卡,两通道一个用发送报文,另一个用来接收报文。之前想过再起一个线程,用来接收报文,并把报文发送到QTextEdit当中,这种方法也实现不了。想用异步发送,然后在总线中进行轮询,还没有实施,我感觉也够呛。
编译器用的Pycharm,CAN卡是busmaster,我试过简单的发送和接受报文,这个可以实现,利用can.listenner监听报文,也可以实现,但到了Pyqt5 里面用QThread实现起来有点困难,主线程定义了操作面板,子线程用来发送,总感觉还少了点什么,没办法,刚开始学!

我试了一下,报错如下:

img

我也查了一下bus.py源文档,没有subscribe函数,因此,如果要想启用监听listener,我尝试了can.Notifier,但还是监听不到报文:

img

不知道你这个问题是否已经解决, 如果还没有解决的话:
  • 以下回答来自chatgpt:

    首先,要确保CAN报文在Python-can中能够正常发送和接收。如果你能够成功地发送和接收报文,那么至少证明你的CAN卡与电脑连接正确。然后,我们需要将接收到的CAN报文显示在PyQt5的QTextEdit控件中。

    我们可以通过继承QThread类来创建一个新线程,用于接收CAN报文。在新线程中,需要使用Python-can中的listener类来监听总线上的报文。一旦监听到报文,我们可以使用PyQt5的信号槽系统将报文发送回主线程,以便在QTextEdit中显示。

    以下代码是一个简单的示例:

    from PyQt5.QtCore import QThread, pyqtSignal
    import can
    
    class ReceiverThread(QThread):
        message_received = pyqtSignal(str)
    
        def __init__(self, bus):
            super(ReceiverThread, self).__init__()
            self.bus = bus
    
        def run(self):
            listener = can.BufferedReader()
            self.bus.subscribe(listener)
            while True:
                msg = listener.get_message()
                data = msg.data.hex()
                self.message_received.emit(data)
    

    在这个示例中,我们使用了BufferedReader类来监听CAN报文。在run方法中,我们使用了一个无限循环来不断监听来自总线的报文。当有报文时,我们将报文的十六进制数据转换为字符串,并使用message_received信号将报文发送回主线程。

    接下来,我们需要在主线程中创建一个QTextEdit控件,并将message_received信号连接到一个槽函数,以便在QTextEdit中显示报文。以下是一个简单的代码片段:

    from PyQt5.QtWidgets import QTextEdit, QApplication
    from PyQt5.QtCore import pyqtSlot
    
    class Window(QMainWindow):
        def __init__(self, bus):
            super(Window, self).__init__()
            self.setWindowTitle("CAN Bus Monitor")
            self.text_edit = QTextEdit()
            self.setCentralWidget(self.text_edit)
            self.receiver_thread = ReceiverThread(bus)
            self.receiver_thread.message_received.connect(self.update_text_edit)
            self.receiver_thread.start()
    
        @pyqtSlot(str)
        def update_text_edit(self, message):
            self.text_edit.append(message)
    

    在这个示例中,我们在主线程中创建了一个QTextEdit控件,并将其设置为MainWindow的中央小部件。我们还创建了一个ReceiverThread对象,并将message_received信号连接到一个名为update_text_edit的槽函数。当收到新报文时,槽函数会将报文附加到QTextEdit中。

    最后,我们需要使用Python-can模块中的can.Message类来发送CAN报文。以下是一个简短的示例代码:

    bus = can.interface.Bus(bustype='pcan', channel='PCAN_USBBUS1', bitrate=250000)
    msg = can.Message(arbitration_id=0x123, data=[0x01, 0x02, 0x03])
    bus.send(msg)
    

    在这个示例中,我们首先创建了一个CAN总线对象,指定了总线类型和通道。然后,我们使用can.Message类创建了一个带有特定ID和数据的CAN报文。最后,我们使用总线对象的send方法发送报文。

    综上所述,针对该问题,我们需要解决以下几个方面:

    1. 确保CAN总线能够正常发送和接收报文
    2. 创建一个继承自QThread的新线程,用于监听来自总线的CAN报文
    3. 在主线程中创建一个QTextEdit控件,并将新报文发送到该控件中显示。
    4. 使用Python-can模块中的can.Message类来发送CAN报文。

    如果以上步骤都正确地完成了,那么你的小程序应该可以正常地发送和接收CAN报文,并在QTextEdit控件中显示报文。


如果你已经解决了该问题, 非常希望你能够分享一下解决方案, 写成博客, 将相关链接放在评论区, 以帮助更多的人 ^-^