尝试从外部脚本更新进度条时,QWidget 变得无响应[重复]

Posted

技术标签:

【中文标题】尝试从外部脚本更新进度条时,QWidget 变得无响应[重复]【英文标题】:QWidget becomes unresponsive when trying to update progressbar from external script [duplicate] 【发布时间】: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)

【问题讨论】:

【参考方案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 的答案,它可能会让您了解更好的(和建议的)线程方法。

【讨论】:

以上是关于尝试从外部脚本更新进度条时,QWidget 变得无响应[重复]的主要内容,如果未能解决你的问题,请参考以下文章

从 powershell 下载文件时,Invoke-WebRequest 进度变得无响应/暂停

显示进度条时如何暂停 Selenium 执行

进入主队列后 UI 变得无响应

如何将 QWidget 类中的 lineedit 字符串共享到工作线程

如何在显示firebase数据获取的进度条时通过startListening()解决错误? [重复]

在 qwidget 中运行外部应用程序