pyqt 中使用threading创建子线程,子线程与主线程无法并发的解决办法

一、问题描述

1、以下代码实现的功能是:使用串口向下面的终端发送数据,然后创建一个线程接受终端传过来的上行数据帧。

2、问题所在:在线程运行之前,串口下发数据帧的函数已经执行完毕,是可以在UI界面体现出写操作的(主线程try:中的操作)。但是实际使用中,主线程的操作总是等子线程结束后才在UI界面体现出来。我认为是主线程和子线程没有实现并发操作。

# 这里是主线程,用于通过串口下发数据
def SendDownData(self, data, printdata):
    if self.ser.is_open:
        try:
            # 以下的操作,如self.textBrowser.append()应该在UI界面的textBrowser中打印出来
            # 但事实上,总是等待子线程完成后才实现
            self.ser.flushInput()#丢弃接收缓存中的所有数据,防止接受到串口的垃圾数据
            self.senddata = bytes.fromhex(data)  # 字符转成字节
            self.ser.write(self.senddata)

            ct = datetime.datetime.now()
            ct_str = ct.strftime("%Y-%m-%d %H:%M:%S")
            ct_str = '[ ' + ct_str + ' ]' + ': '
            self.textBrowser.append('- - - - - - - - - - - - - -下行报文 - - - - - - - - - - - - - - - - ' + '\n')
            self.textBrowser.append(ct_str + '下行报文已发送')
            self.textBrowser.append(ct_str + '发送的报文为:')

            #给字符串数据帧的每一个字节后面加一个空格
            printdowndata = re.findall(".{2}", data)
            printdowndata = " ".join(printdowndata)
            self.textBrowser.append(printdowndata)
            self.textBrowser.append(printdata)
            self.textBrowser.append('- - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -')          
            self.Create_thread()

        except Exception as e:
            pass
    else:
        QMessageBox.warning(self, '提示信息', '串口未打开!', QMessageBox.Ok,
                        QMessageBox.Ok)

# 创建子线程
def Create_thread(self):
    self.WaitingUpDatathread = threading.Thread(target=self.ReadUpData)
    self.WaitingUpDatathread.setDaemon(True)
    self.WaitingUpDatathread.start()
    self.WaitingUpDatathread.join()

# 子线程,使用串口接受终端响应的数据帧
def ReadUpData(self):
    self.readstrdata = ''
    self.timeflag = 0 #目的是让延时接受最长为3秒

    while self.timeflag != 30:
        self.timeflag += 1
        time.sleep(0.1)
        self.readbytesdata = self.ser.read_all()
        self.readstrdata = self.readstrdata + self.readbytesdata.hex()  # 字节转成16进制字符显示
        # 接受到最短数据帧就结束循环
        if len(self.readstrdata) >= 40:
            break
        print("上行数据帧:" + self.readstrdata)
    self._Signal_GetData.emit(self.readstrdata)

 左侧的下行报文的打印内容是主线程实现的,它总是在右侧子线程打印之后打印。

二、解决办法

1、解决办法就是抛弃threading库写子线程,而是使用pyqt提供的QThread库写子线程,以下是我针对我的项目的代码改写。

    #创建子线程的函数
    def Create_thread(self):
        self.ReadUpData = ReadupdataThread(self.ser)
        self.ReadUpData._Updata_Signal.connect(self.ReadUpDatasig)
        self.ReadUpData.start()

    def ReadUpDatasig(self, data):
        self._Signal_GetData.emit(data)

# 子线程类
class ReadupdataThread(QThread):
    # # pyqtSignal是信号类
    _Updata_Signal = pyqtSignal(str)        # 计数完成后发送一个信号
    def __init__(self, ser):
        super().__init__()  ## 继承QThread
        self.ser = ser

    def run(self):
        readstrdata = ''
        timeflag = 0  # 目的是让延时接受最长为3秒

        while timeflag != 30:
            timeflag += 1
            time.sleep(0.1)
            readbytesdata = self.ser.read_all()
            readstrdata = readstrdata + readbytesdata.hex()  # 字节转成16进制字符显示
            if len(readstrdata) >= 40:
                break
            print("上行数据帧:" + readstrdata)
        self._Updata_Signal.emit(readstrdata)

  • 1
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
PyQt 的多线程编程,如果你的线程没有访问线程的标签,可能是因为你没有正确地使用信号与槽机制。 具体来说,你可以在线程定义一个槽函数,用于更新标签的文本,然后在线程发射这个信号,从而触发这个槽函数。以下是一个简单的示例代码: ```python from PyQt5.QtCore import QThread, pyqtSignal class MyThread(QThread): update_signal = pyqtSignal(str) def run(self): while True: text = "当前时间:{}".format(datetime.now()) self.update_signal.emit(text) time.sleep(1) class MainWindow(QMainWindow): def __init__(self): super().__init__() self.label = QLabel() self.setCentralWidget(self.label) self.thread = MyThread() self.thread.update_signal.connect(self.update_label) self.thread.start() def update_label(self, text): self.label.setText(text) ``` 在上面的代码,`MyThread` 类继承自 `QThread`,并定义了一个 `update_signal` 信号,用于在线程更新标签的文本。`MainWindow` 类继承自 `QMainWindow`,并包含一个标签 `label`。在 `MainWindow` 的构造函数创建一个 `MyThread` 的实例,并将它的 `update_signal` 信号连接到 `MainWindow` 的 `update_label` 槽函数上。然后,启动线程,这样,每隔一秒钟,线程就会发射 `update_signal` 信号,从而触发 `update_label` 槽函数,在线程更新标签的文本。 请注意,在使用 PyQt 的多线程编程时,应该避免直接访问线程的 UI 元素,因为这样会导致线程不安全的问题。相反,你应该使用信号与槽机制来实现线程间的通信。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值