使用以下代码时,我的应用程序会在几秒钟后停顿。我指的是档位。我从Windows看到一个窗口,说等待或强制关闭。
我可能会补充说,只有在进度条窗口中单击或在进度条窗口外部单击时,才会发生这种情况,从而失去焦点。如果我启动该示例,并且不进行任何操作,它将像应该的那样工作。
from PyQt4 import QtCore
from PyQt4 import QtGui
class ProgressBar(QtGui.QWidget):
def __init__(self, parent=None, total=20):
super(ProgressBar, self).__init__(parent)
self.name_line = QtGui.QLineEdit()
self.progressbar = QtGui.QProgressBar()
self.progressbar.setMinimum(1)
self.progressbar.setMaximum(total)
main_layout = QtGui.QGridLayout()
main_layout.addWidget(self.progressbar, 0, 0)
self.setLayout(main_layout)
self.setWindowTitle("Progress")
def update_progressbar(self, val):
self.progressbar.setValue(val)
这样使用:
app = QtGui.QApplication(sys.argv)
bar = ProgressBar(total=101)
bar.show()
for i in range(2,100):
bar.update_progressbar(i)
time.sleep(1)
谢谢你的帮助。
您需要允许在循环运行时处理事件,以便应用程序可以保持响应状态。
更重要的是,对于长时间运行的任务,您需要提供一种让用户在循环开始后就停止循环的方法。
一种简单的方法是使用计时器启动循环,然后在循环运行时定期调用qApp.processEvents。
这是一个演示脚本,可以执行此操作:
import sys, time
from PyQt4 import QtGui, QtCore
class ProgressBar(QtGui.QWidget):
def __init__(self, parent=None, total=20):
super(ProgressBar, self).__init__(parent)
self.progressbar = QtGui.QProgressBar()
self.progressbar.setMinimum(1)
self.progressbar.setMaximum(total)
self.button = QtGui.QPushButton('Start')
self.button.clicked.connect(self.handleButton)
main_layout = QtGui.QGridLayout()
main_layout.addWidget(self.button, 0, 0)
main_layout.addWidget(self.progressbar, 0, 1)
self.setLayout(main_layout)
self.setWindowTitle('Progress')
self._active = False
def handleButton(self):
if not self._active:
self._active = True
self.button.setText('Stop')
if self.progressbar.value() == self.progressbar.maximum():
self.progressbar.reset()
QtCore.QTimer.singleShot(0, self.startLoop)
else:
self._active = False
def closeEvent(self, event):
self._active = False
def startLoop(self):
while True:
time.sleep(0.05)
value = self.progressbar.value() + 1
self.progressbar.setValue(value)
QtGui.qApp.processEvents()
if (not self._active or
value >= self.progressbar.maximum()):
break
self.button.setText('Start')
self._active = False
app = QtGui.QApplication(sys.argv)
bar = ProgressBar(total=101)
bar.show()
sys.exit(app.exec_())
更新
假设您使用的是python的C实现(即CPython),则此问题的解决方案 完全
取决于必须与GUI并行运行的任务的性质。从根本上讲,它是由具有全局解释器锁(GIL)的CPython确定的。
我不会尝试对CPython的GIL进行任何解释:相反,我只建议您观看Dave
Beazley的这段出色的PyCon视频,然后就此结束。
通常,在尝试与后台任务同时运行GUI时,要问的第一个问题是:任务是IO绑定还是CPU绑定?
如果是IO绑定的(例如,访问本地文件系统,从Internet下载等),则该解决方案通常非常简单,因为CPython始终为I /
O操作发布GIL。后台任务可以简单地以异步方式完成,也可以由工作线程执行,而无需执行任何特殊操作即可使GUI保持响应。
当遇到第二个问题要问时,主要的困难出现在与CPU绑定的任务上:可以将任务分解为一系列小步骤吗?
如果可以,那么解决方案是定期向GUI线程发送请求,以处理其当前的未决事件堆栈。上面的演示脚本是该技术的粗略示例。通常,任务将在单独的工作线程中执行,当任务的每个步骤完成时,该线程会发出gui更新信号。(注意:重要的是要确保工作线程自己绝不要尝试任何与GUI相关的操作)。
但是,如果 不能 将任务分解成小步,那么所有常规的线程类型解决方案都将无法正常工作。无论是否使用线程,GUI都将冻结直到任务完成。
对于此最终方案,唯一的解决方案是使用单独的 进程
,而不是单独的线程-即,使用多处理模块。当然,只有目标系统具有多个可用的CPU内核时,此解决方案才有效。如果只有一个CPU内核可以使用,那么基本上没有什么可以提供帮助的(除了切换到Python的不同实现,或者完全切换到另一种语言)。