提问人:chris1656 提问时间:11/15/2023 最后编辑:chris1656 更新时间:11/20/2023 访问量:34
为什么 PySide6 应用程序在 QThreadPool 中执行多个 QRunnables 时将鼠标悬停在自定义按钮上时崩溃
Why PySide6 application crashes when hovering over custom button while executing several QRunnables in QThreadPool
问:
我在 Stackoverflow 上的第一个问题:我会尽力解释这个问题;
我目前正在使用基于 PySide6 的 Python 应用程序。
有几个耗时的计算作为实例运行。到目前为止,一切正常。QRunnable
QThreadPool.globalInstance()
我还对 UI 进行了修改。现在的问题是,当我在后台运行时将鼠标悬停在按钮上时,应用程序崩溃了。QPushButton
QRunnables
我创建了一个最小的可重复示例。一个非常简单的工作线程 (),它只等待 1 秒,完成后发出 finish。QRunnable
Signal
文件q_worker.py
from PySide6.QtCore import QObject, QRunnable, Signal, Slot
from time import sleep
class WorkerSignals(QObject):
finished = Signal()
class WorkerSleep(QRunnable):
def __init__(self):
super(WorkerSleep, self).__init__()
self.signals = WorkerSignals()
@Slot()
def run(self):
sleep(1)
self.signals.finished.emit()
在中找到仅覆盖方法的类。此外,将创建一个带有 1 和 1 的窗口。main.py
CustomButton
paintEvent
CustomButton
QLabel
文件 main.py
import sys
import os
from PySide6.QtWidgets import QApplication, QMainWindow, QWidget, QLabel, QVBoxLayout, QPushButton
from PySide6.QtCore import Qt, QThreadPool, QTimer, Slot
from PySide6.QtGui import QPainter, QPaintEvent, QLinearGradient
from q_worker import WorkerSleep
class CustomButton(QPushButton):
def __init__(self, parent=None):
super(CustomButton, self).__init__(parent)
self.setFixedSize(650, 99)
def paintEvent(self, event: QPaintEvent):
fill_color = QLinearGradient.Preset.TemptingAzure
with QPainter(self) as p:
p.setRenderHint(QPainter.RenderHint.Antialiasing)
rect = event.rect()
p.fillRect(rect, fill_color)
class MainWindow(QMainWindow):
def __init__(self):
super(MainWindow, self).__init__()
# set window title
self.setWindowTitle('minimal reproducible example')
# time in seconds, before workers are created
self._count = 5
# number of workers
self._num_workers_to_create = 100
self._num_workers_completed = 0
self._setup_ui()
self.show()
# start countdown to create workers
self._timer = QTimer(self)
self._timer.timeout.connect(self._countdown)
self._timer.start(1000)
def _setup_ui(self):
central_widget = QWidget()
self.setCentralWidget(central_widget)
central_widget_layout = QVBoxLayout(central_widget)
# add ui elements
self.label_counter = QLabel(f"<span style= font-size:25pt>{self._count}</span>")
central_widget_layout.addWidget(self.label_counter, alignment=Qt.AlignmentFlag.AlignHCenter)
central_widget_layout.addWidget(CustomButton(parent=self))
@Slot()
def _countdown(self):
self._count -= 1
self.label_counter.setText(f"<span style= font-size:25pt>{self._count}</span>")
if self._count == 0:
self._timer.stop()
self._create_workers()
def _create_workers(self):
for i in range(self._num_workers_to_create):
worker = WorkerSleep()
worker.signals.finished.connect(self._update_completed_workers)
QThreadPool.globalInstance().start(worker)
@Slot()
def _update_completed_workers(self):
num_threads = str(QThreadPool.globalInstance().activeThreadCount())
self._num_workers_completed += 1
self.label_counter.setText(f"<span style= font-size:25pt>"
f"{self._num_workers_completed} Workers completed "
f"({num_threads} Threads running)</span>")
def main():
app = QApplication(sys.argv)
mw = MainWindow()
app.exec()
if __name__ == "__main__":
sys.exit(main())
运行该示例时,窗口打开,计时器倒计时 5 秒,然后在 中启动 100 次。只要我不将鼠标悬停在按钮上,一切正常。但是,当我在处理工作线程时将鼠标悬停在按钮上时,应用程序崩溃了。WorkerSleep
QThreadPool.globalInstance()
起初我以为是因为添加的太多了。但是,根据文档,当到达时,它们将被排队。这似乎可以完美地工作,因为默认值始终为 8。QRunnables
QThreadPool.globalInstance()
QThreadPool.maxThreadCount()
QThreadPool.globalInstance().activeThreadCount()
经过进一步尝试后,问题似乎出在 .因为如果使用标准,一切都会完美运行。CustomButton
QPushButton
因此,如果我删除自定义,一切都按预期工作。所以这种方法似乎有问题。但是无论我尝试对这种方法进行什么更改,它都会崩溃。paintEvent
最后但并非最不重要的一点是,还有另一个我无法解释的超级奇怪的现象:当我用较小的尺寸初始化按钮时
class CustomButton(QPushButton):
def __init__(self, parent=None):
super(CustomButton, self).__init__(parent)
self.setFixedSize(650, 50)
该应用程序在我和我的自定义下运行良好。CustomButton
paintEvent
我正在运行 Windows 10、Python 3.9.9 和 PySide6 v.6.4.1
我尝试了以下方法:
- 添加到没有解决问题
setAutoDelete(False)
WorkerSleep.__init__
- 在 venv 中从 (Windows) 控制台运行会导致相同的结果
- 我还尝试了使用新 venv 的完全不同的 Windows 机器 - 从控制台运行会导致相同的结果
- 我将 PySide6 版本升级到当前的 v.6.6.0 并查看此处 - 然后它起作用了
我无法解决 Python 3.9.9 和 PySide 6.4.1 的问题?
答: 暂无答案
评论
setAutoDelete(False)
::clear()
self.setAutoDelete(False)
__init__
autoDelete()
worker