【问题标题】:Why do external functions cause the PyQt5 window to freeze?为什么外部函数会导致 PyQt5 窗口冻结?
【发布时间】:2017-08-18 21:12:40
【问题描述】:

以下是一些中断的示例代码:

import sys
import time
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

        self.count = 0

        while self.count < 100:
            self.count += 1
            time.sleep(1) # Example external function
            self.progress.setValue(self.count)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    sys.exit(app.exec_())

运行它会导致它冻结并变得无响应,尤其是在 Windows 环境中。用任何非 PyQt5 函数替换 time.sleep 函数将产生相同的结果。

据我了解,这与未在使用 QThread 的单独线程中调用的函数有关。我使用this answer 作为参考,并提出了部分解决方案。

import sys
import time

from PyQt5.QtCore import QThread
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class External(QThread):

    def run(self):
        count = 0

        while count < 100:
            count += 1
            print(count)
            time.sleep(1)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    calc = External()
    calc.finished.connect(app.exit)
    calc.start()
    sys.exit(app.exec_())

这将在后台运行time.sleep 并保持主窗口响应。但是,我不知道如何使用self.progress.setValue 更新这些值,因为在External 类中无法访问它。

据我所知,我必须使用信号来完成此操作。那里的大多数文档都是针对 PyQt4 的,这使得找到解决方案变得更加困难。

我面临的另一个问题是能够从 Actions 类中启动 External 线程。

这个问题的答案也将作为 PyQt5 的宝贵文档。 提前致谢。

【问题讨论】:

标签: python pyqt python-3.5 pyqt5 qthread


【解决方案1】:

您必须使用信号来更新值。

import sys
import time

from PyQt5.QtCore import QThread, pyqtSignal
from PyQt5.QtWidgets import (QApplication, QDialog,
                             QProgressBar)

class External(QThread):
    countChanged = pyqtSignal(int)
    def run(self):
        count = 0

        while count < 100:
            count += 1
            self.countChanged.emit(count)
            print(count)
            time.sleep(1)

class Actions(QDialog):
    def __init__(self):
        super().__init__()
        self.initUI()

    def initUI(self):
        self.progress = QProgressBar(self)
        self.progress.setGeometry(0, 0, 300, 25)
        self.show()

    def onCountChanged(self, value):
        self.progress.setValue(value)

if __name__ == "__main__":
    app = QApplication(sys.argv)
    window = Actions()
    calc = External()
    calc.countChanged.connect(window.onCountChanged)
    calc.start()
    sys.exit(app.exec_())

【讨论】:

    【解决方案2】:

    这是一个从 Actions 类内部启动线程并使用按钮的版本:

    import sys
    import time
    
    from PyQt5.QtCore import QThread, pyqtSignal
    from PyQt5.QtWidgets import (QApplication, QDialog,
                                 QProgressBar, QPushButton)
    
    class External(QThread):
    
        countChanged = pyqtSignal(int)
    
        def run(self):
            count = 0
    
            while count < 100:
                count += 1
                time.sleep(1)
                print(count)
                self.countChanged.emit(count)
    
    class Actions(QDialog):
        def __init__(self):
            super().__init__()
            self.initUI()
    
        def initUI(self):
            self.progress = QProgressBar(self)
            self.progress.setGeometry(0, 0, 300, 25)
            self.button = QPushButton('Start', self)
            self.button.move(0, 30)
            self.show()
    
            self.button.clicked.connect(self.onButtonClick)
    
        def onButtonClick(self):
            self.calc = External()
            self.calc.countChanged.connect(self.onCountChanged)
            self.calc.start()
    
        def onCountChanged(self, value):
            self.progress.setValue(value)
    
    if __name__ == "__main__":
        app = QApplication(sys.argv)
        window = Actions()
        sys.exit(app.exec_())
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2020-09-13
      • 1970-01-01
      • 2017-12-03
      • 1970-01-01
      • 2019-12-16
      • 2013-12-11
      • 2023-03-06
      相关资源
      最近更新 更多