PySide2/QT for Python:小部件未更新/GUI 冻结

PySide2/QT for Python : Widget not updating / GUI Freezing

我在 python 中使用 pyside2。在 Qmainwindow 上,我创建了一个 QpushButton 和一个 Qlabel。标签隐藏在 mainWindow 的初始位置,pushButton 连接到以下函数,定义在 mainWindow 中:

def buttonPushed(self):
        self.label.show()
        self.doStuff()
        self.label.hide()

"doStuff()" 函数需要 15 秒的执行时间并按预期工作,因此此时标签应该可见,但事实并非如此。如果我删除 "self.label.hide()",标签会显示(当然不会再隐藏)。

"doStuff()"函数调用了pyside2的函数。 我还尝试在 self.label.show() 之后添加一个 self.label.update(),但没有任何区别。

我的猜测是这与 QT 调度任务的方式有关:当我调用 self.label.show() 时,QT 仅在 buttonPushed() 结束后执行此操作。

我该怎么办?

如果一个任务执行了很长时间,它会阻塞Qt事件循环导致某些事件无法正常工作,因为事件无法传输导致window冻结,产生什么效果你指出。

因此在这些情况下,您必须在另一个线程中执行该任务(假设该任务不直接修改 GUI)并通过信号将信息发送到 GUI 线程。在你的情况下,必须在执行繁重的任务之前发出一个信号,在它们分别连接到 QLabel 的显示和隐藏方法之后发出另一个信号。

import threading

from PySide2.QtCore import Signal

class MainWindow(QMainWindow):
    started = Signal()
    finished = Signal()

    def __init__(self, parent=None):
        super().__init__(parent)

        # ...

        self.started.connect(self.label.show)
        self.finished.connect(self.label.hide)

        self.button.clicked.connect(self.buttonPushed)

    def buttonPushed(self):
        threading.Thread(target=self.doStuff, daemon=True).start()

    def doStuff(self):
        self.started.emit()
        # heavy task
        self.finished.emit()

@eyllanesc 的解决方案在线程中的任务不涉及 QT 时有效。否则应该使用 QThread 和 Qthreadpool。我用这个 tutorial 来了解如何做,但这里有一个小例子:

from PySide2.QtCore import  Signal, QRunnable, QThreadPool, QObject

class MainWindow(QMainWindow):

    def __init__(self, parent=None):
        super().__init__(parent)

        # [...]

        self.threadpool = QThreadPool()
        self.button.clicked.connect(self.buttonPushed)

    def buttonPushed(self):
        builder = Builder()

        builder.signals.started.connect(self.label.show)
        builder.signals.finished.connect(self.label.hide)
        builder.signals.result.connect(self.doStuff)

        self.threadpool.start(builder)

    # a function that use the heavy task's results
    def doStuff(self, *args):
    # [...]

#defining the signals that our thread will use
class BuilderSignals(QObject):

    started = Signal()
    finished = Signal()
    result = Signal(*args)

#defining our thread
class Builder(QRunnable):
    def __init__(self,parent=None):
        super(Builder, self).__init__()
        self.signals = BuilderSignals()

    def run(self):
        self.signals.started.emit()
        #heavy task involving PySide2
        self.signals.result.emit(*args)
        self.signals.finished.emit()