如果使用下面的代码我的应用程序几秒钟后档。 和摊点我的意思是挂起。 我收到从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_())
UPDATE
假设你正在使用的C语言实现的Python(即CPython的),解决这个问题完全取决于必须与GUI同时运行的任务(一个或多个)的性质。 更重要的是,它是由具有确定的CPython 全局解释器锁(GIL) 。
我不打算尝试的CPython的GIL的任何解释;相反,我会简单地推荐看这部优秀PYCON视频由Dave比兹利,并留在这一点。
一般情况下,试图用一个后台任务同时运行GUI的时候,第一个要问的问题是:是任务IO的限制,或CPU绑定?
如果是IO的限制(例如,访问本地文件系统,从互联网上下载,等等),那么解决方案通常是非常简单的,因为CPython的总释放GIL的I / O操作。 后台任务可以简单地实现异步 ,或由执行工作线程 ,并做什么特别的需求,保证GUI作出响应。
的主要困难与发生CPU密集型任务,当有第二个问题要问:可以将任务分解成一系列小步骤?
如果可以,那么解决的办法是定期发送请求到GUI线程来处理目前的未决事件的堆栈。 上述演示脚本是该技术的粗例子。 更通常,所述任务将在一个单独的工作线程,作为任务的各步骤完成,其将发射的GUI更新信号来进行。 (注:它确保了工作线程不会尝试任何GUI相关的操作本身是很重要的)。
但是,如果任务不能被分解成小的步骤,那么没有通常线程型的解决方案会奏效。 该GUI将只是冻结,直到任务已经完成,线程是否使用与否。
对于这最后的情况下,唯一的解决办法是使用一个单独的进程 ,而不是一个单独的线程-即利用的多模块。 当然,如果目标系统具有多个可用的CPU内核,该解决方案才会有效。 如果只有一个CPU核心一起玩,还有基本上没有什么可以做,以帮助(而不是切换到不同的Python实现,或以不同的语言完全)。
当你GUI编程需要使用某种形式的多线程的,你将有一个工作线程和一个更新GUI和响应鼠标和键盘事件。 有许多方法可以做到这一点。 我建议你看看这个QProgressBar教程有如何使用QProgressBar一个很好的工作示例。
在本教程中他们使用QBasicTimer是办法得到控制回主线程,以便它可以以GUI事件。 通过使用time.sleep
在你的代码是阻止一秒钟运行的唯一线索。