You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

线程循环更新QPixmap触发段错误问题求助

解决PyQt5跨线程更新GUI导致的段错误问题
  • 问题根源:PyQt的所有GUI操作(包括setPixmap)必须在主线程执行,直接在子线程中调用setPixmap属于跨线程操作GUI,会破坏Qt的GUI线程安全机制,引发内存访问错误,最终触发段错误。

  • 核心解决方案:用信号槽机制实现线程间通信

    1. 自定义线程类,只负责读取HC-SR04的距离数据,不做任何GUI操作
    2. 在线程类中声明信号,用于传递距离数据到主线程
    3. 主线程中连接信号到槽函数,在槽函数里完成Pixmap的更新操作
  • 具体代码示例
    首先是自定义距离检测线程:

    from PyQt5.QtCore import QThread, pyqtSignal
    import RPi.GPIO as GPIO
    import time
    
    class DistanceThread(QThread):
        distance_updated = pyqtSignal(float)  # 传递距离数据的信号
    
        def __init__(self, trig_pin, echo_pin):
            super().__init__()
            self.trig_pin = trig_pin
            self.echo_pin = echo_pin
            self.running = True
            # 初始化HC-SR04的GPIO引脚
            GPIO.setmode(GPIO.BCM)
            GPIO.setup(trig_pin, GPIO.OUT)
            GPIO.setup(echo_pin, GPIO.IN)
    
        def run(self):
            while self.running:
                # 读取HC-SR04的距离值
                GPIO.output(self.trig_pin, False)
                time.sleep(0.000002)
                GPIO.output(self.trig_pin, True)
                time.sleep(0.00001)
                GPIO.output(self.trig_pin, False)
                
                while GPIO.input(self.echo_pin) == 0:
                    signal_off = time.time()
                while GPIO.input(self.echo_pin) == 1:
                    signal_on = time.time()
                
                time_passed = signal_on - signal_off
                distance = time_passed * 17000  # 转换为厘米
                self.distance_updated.emit(distance)  # 发射距离信号
                time.sleep(0.1)  # 控制检测频率,避免频繁更新
    
        def stop(self):
            self.running = False
            self.wait()
            GPIO.cleanup()  # 清理GPIO资源
    

    然后是主窗口类,负责GUI更新:

    from PyQt5.QtWidgets import QMainWindow, QLabel
    from PyQt5.QtGui import QPixmap
    
    class Dashboard(QMainWindow):
        def __init__(self):
            super().__init__()
            # 预加载所有状态的Pixmap,避免重复加载浪费资源
            self.pixmaps = {
                "front_1a": {"on": QPixmap("front_1a_on.png"), "off": QPixmap("front_1a_off.png")},
                "front_1b": {"on": QPixmap("front_1b_on.png"), "off": QPixmap("front_1b_off.png")},
                "front_1c": {"on": QPixmap("front_1c_on.png"), "off": QPixmap("front_1c_off.png")},
                "front_1d": {"on": QPixmap("front_1d_on.png"), "off": QPixmap("front_1d_off.png")}
            }
    
            # 初始化标签并设置初始状态
            self.front_1a_label = QLabel(self)
            self.front_1a_label.setPixmap(self.pixmaps["front_1a"]["off"])
            self.front_1b_label = QLabel(self)
            self.front_1b_label.setPixmap(self.pixmaps["front_1b"]["off"])
            self.front_1c_label = QLabel(self)
            self.front_1c_label.setPixmap(self.pixmaps["front_1c"]["off"])
            self.front_1d_label = QLabel(self)
            self.front_1d_label.setPixmap(self.pixmaps["front_1d"]["off"])
            # 这里可以添加标签的布局设置,比如位置、大小等
    
            # 启动距离检测线程并连接信号槽
            self.distance_thread = DistanceThread(trig_pin=23, echo_pin=24)
            self.distance_thread.distance_updated.connect(self.update_pixmaps)
            self.distance_thread.start()
    
        def update_pixmaps(self, distance):
            # 根据距离判断并切换对应标签的Pixmap
            threshold = 30  # 自定义预警距离阈值(厘米)
            status = "on" if distance < threshold else "off"
            
            self.front_1a_label.setPixmap(self.pixmaps["front_1a"][status])
            self.front_1b_label.setPixmap(self.pixmaps["front_1b"][status])
            self.front_1c_label.setPixmap(self.pixmaps["front_1c"][status])
            self.front_1d_label.setPixmap(self.pixmaps["front_1d"][status])
    
        def closeEvent(self, event):
            # 窗口关闭时停止线程,避免资源泄漏
            self.distance_thread.stop()
            event.accept()
    
  • 额外优化点

    • 预加载Pixmap:一次性加载所有需要的图片资源,避免每次更新时重复读取文件,提升性能
    • 控制检测频率:线程中添加time.sleep()避免过于频繁的距离检测和GUI更新
    • 资源清理:退出程序时停止线程并清理GPIO,防止树莓派引脚资源泄漏

内容的提问来源于stack exchange,提问作者Pasindu Danthanarayana

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.17 07:53:11