PySide6程序在QThreadPool运行QRunnable时Hover自定义按钮崩溃
解决方案(适配Python3.9.9 + PySide6 v6.4.1)
针对你遇到的自定义按钮hover时程序崩溃的问题,以下是几个可行的修复方案,均适配旧版本环境:
方案1:调用父类paintEvent处理基础状态
你的自定义paintEvent完全覆盖了父类实现,导致Qt内部的hover状态管理、绘图上下文清理等逻辑未执行,在并发场景下引发冲突。修改CustomButton的paintEvent:
def paintEvent(self, event: QPaintEvent): # 先让父类处理按钮的基础状态(包括hover标记、内部绘图资源) super().paintEvent(event) fill_color = QLinearGradient.Preset.TemptingAzure with QPainter(self) as p: p.setRenderHint(QPainter.RenderHint.Antialiasing) rect = event.rect() p.fillRect(rect, fill_color)
如果不需要保留父类的默认按钮样式,可以添加p.setCompositionMode(QPainter.CompositionMode_Source)实现完全覆盖绘制,但必须先调用父类paintEvent完成基础状态初始化。
方案2:禁用按钮的hover事件
如果业务不需要按钮的hover交互,可以直接关闭hover状态,避免触发冲突的重绘逻辑:
class CustomButton(QPushButton): def __init__(self, parent=None): super(CustomButton, self).__init__(parent) self.setFixedSize(650, 99) # 禁用hover事件,不会触发hover相关的重绘 self.setAttribute(Qt.WA_Hover, False)
方案3:使用本地线程池替代全局实例
全局QThreadPool实例在旧版本PySide6中可能存在与UI线程的状态同步问题,改用本地线程池实例:
class MainWindow(QMainWindow): def __init__(self): super(MainWindow, self).__init__() # ... 其他初始化代码 ... # 创建本地线程池实例 self._thread_pool = QThreadPool() def _create_workers(self): for i in range(self._num_workers_to_create): worker = WorkerSleep() worker.signals.finished.connect(self._update_completed_workers) # 使用本地线程池启动任务 self._thread_pool.start(worker)
方案4:手动创建渐变替代预设值
旧版本中QLinearGradient.Preset可能存在线程安全问题,手动创建渐变替代预设值:
def paintEvent(self, event: QPaintEvent): # 手动创建渐变,模拟TemptingAzure效果 gradient = QLinearGradient(0, 0, self.width(), self.height()) gradient.setColorAt(0, QColor(100, 181, 246)) gradient.setColorAt(1, QColor(144, 202, 249)) with QPainter(self) as p: p.setRenderHint(QPainter.RenderHint.Antialiasing) rect = event.rect() p.fillRect(rect, gradient)
问题原因
这是PySide6 v6.4.x版本的已知bug,涉及自定义控件paintEvent与QThreadPool并发操作时的绘图资源冲突:当后台线程触发UI更新信号时,大尺寸自定义按钮的hover重绘会触发内存访问错误。官方在v6.6.0版本中修复了该类线程与UI绘图的同步问题,因此升级后问题消失。
内容的提问来源于stack exchange,提问作者chris1656
相关产品推荐
相关产品推荐

