【问题标题】:QWidget becomes unresponsive when trying to update progressbar from external script [duplicate]尝试从外部脚本更新进度条时,QWidget 变得无响应[重复]
【发布时间】:2019-07-30 16:05:58
【问题描述】:

我正在尝试学习如何在我的 for 循环在外部脚本中运行时更新我的​​主脚本中的进度条。这是我第一次尝试使用信号,所以我不确定我是否正确使用了它们。这是我到目前为止所尝试的。

我尝试做的第一件事是创建一个类“Signal”,它具有跟踪进度条的 pyqtSignal。然后我创建了一个信号对象,并让它在每次 for 循环运行时发出一个信号。然后在我的主脚本中,我尝试将我创建的信号对象连接到进度条的 setValue 方法。进度条更新到 5%,然后窗口变得无响应。关于代码,我有两个主要问题:

窗口无响应的原因是什么?

如何让主脚本中的进度条更新以使窗口不会变得无响应?

ma​​in.py

import sys
from external import *
from PyQt5.QtWidgets import QWidget, QApplication, QProgressBar, 
QPushButton, QVBoxLayout


class Example(QWidget):

    def __init__(self):
        super().__init__()
        self.initUI()


    def initUI(self):
        self.setWindowTitle('Testing')
        self.setGeometry(300, 300, 290, 150)

        self.vbox = QVBoxLayout()
        self.setLayout(self.vbox)

        self.progressbar = QProgressBar(self)
        self.button = QPushButton("run", self)

        self.vbox.addWidget(self.progressbar)
        self.vbox.addWidget(self.button)

        c.update.connect(self.progressbar.setValue)
        self.button.clicked.connect(test) 

        self.show()

if __name__ == '__main__':    
    app = QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

external.py

from PyQt5.QtCore import pyqtSignal, QObject
import time

class Signal(QObject):

    update = pyqtSignal(int) 


c = Signal()   

def test():
    for i in range(100):
        c.update.emit(i)
        time.sleep(1)

【问题讨论】:

    标签: python pyqt5 progress-bar


    【解决方案1】:

    即使 for 循环代码在另一个文件中也没关系,因为它是在 PyQt QApplication 事件循环(以app.exec_() 开头的那个)执行的。
    time.sleep 会阻止一切直到完成,包括 GUI,这就是界面变得无响应的原因。

    您需要在单独的线程中运行循环函数。
    这是一个非常基本的解决方案:

    import threading
    [...]
        def initUI(self):
            [...]
            c.update.connect(self.updateProgressBar)
            self.button.clicked.connect(self.runTest) 
    
            self.show()
    
        def runTest(self):
            threading.Thread(target=test).start()
            self.button.setEnabled(False)
    
        def updateProgressBar(self, value):
            self.progressbar.setValue(value)
            if value == 100:
                self.button.setEnabled(True)
    

    注意:我已将 test 函数的范围设置为 101,因此当它达到 100 时,它会再次启用该按钮,因为我已禁用它以避免多次并发执行该函数。

    也就是说,我不建议您采用这种方法,因为它肯定会在未来产生问题。
    查看this 的答案,它可能会让您了解更好的(和建议的)线程方法。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2013-10-25
      • 1970-01-01
      • 2016-07-07
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多