PySide / Python GUI 冻结
PySide / Python GUI freezes
我目前正在为 rvplayer 编写一个 GUI,它将使艺术家能够自动渲染带有板岩和老化信息的样片。 GUI 使用 PySide 编写并在 Python 2.7 中编写脚本。我的问题是,在调用我的进程并使用标准输出更新我的 QProgressBar
时,GUI 冻结了。我知道这是一个常见问题,可能可以用 processEvents()
以某种方式解决,但我对线程和进程循环知之甚少,无法解决这个问题。由于我的代码已经有点冗长,这里是导致问题的部分:
def rv(self, args):
p = subprocess.Popen(["C:/Program Files/Tweak/RV-4.0.10-64/bin/rvio_hw.exe"]+[x for x in args], stdout=subprocess.PIPE)
while True:
line = p.stdout.readline()
if line != "":
progressStr=re.search(r"([0-9]+.[0-9]+%)", line.rstrip())
if progressStr == None:
print line.rstrip()
else:
progressInt=int(float(re.sub("[^0123456789\.]", "", progressStr.group())))
self.prog_QProgressBar.setValue(progressInt)
print progressStr.group()
else:
break
这是开始我的 QApplication
:
的部分
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
finalForm = MainWindow()
finalForm.show()
sys.exit(app.exec_())
我在按下按钮时调用函数 rv,尽管进度条一直在正常更新,但 window 一段时间后开始变得无响应。我不明白在什么时候我可以使用 app.processEvents()
告诉我的 QApplication 在单独的线程或后台运行进程。
问题是,这并不是说您的应用被冻结,而是 Windows 认为应用被冻结是因为它忽略了事件(鼠标悬停、单击等),所以 Windows,以它的智慧,给你这样的对话。
您需要在 show() 之后关闭线程,然后 运行 processEvents 函数,显然只有在线程完成后才调用 sys.exit。
由于您似乎没有使用线程,可能只需要在更新进度条后调用 processEvents
,如下所示:
self.prog_QProgressBar.setValue(progressInt)
QtGui.qApp.processEvents()
但是,此方法的有效性可能取决于该过程产生输出所需的时间。 processEvents
调用所做的只是立即处理当前在应用程序事件队列中的任何未决事件(例如小部件绘制、鼠标单击等)。在这些调用之间,GUI 将继续冻结(即执行代码不是 运行 在单独的线程中或在后台,正如您所建议的那样)。因此,这种技术可以使 GUI 保持响应的程度取决于 processEvents
在 rv()
方法中的调用频率。
我目前正在为 rvplayer 编写一个 GUI,它将使艺术家能够自动渲染带有板岩和老化信息的样片。 GUI 使用 PySide 编写并在 Python 2.7 中编写脚本。我的问题是,在调用我的进程并使用标准输出更新我的 QProgressBar
时,GUI 冻结了。我知道这是一个常见问题,可能可以用 processEvents()
以某种方式解决,但我对线程和进程循环知之甚少,无法解决这个问题。由于我的代码已经有点冗长,这里是导致问题的部分:
def rv(self, args):
p = subprocess.Popen(["C:/Program Files/Tweak/RV-4.0.10-64/bin/rvio_hw.exe"]+[x for x in args], stdout=subprocess.PIPE)
while True:
line = p.stdout.readline()
if line != "":
progressStr=re.search(r"([0-9]+.[0-9]+%)", line.rstrip())
if progressStr == None:
print line.rstrip()
else:
progressInt=int(float(re.sub("[^0123456789\.]", "", progressStr.group())))
self.prog_QProgressBar.setValue(progressInt)
print progressStr.group()
else:
break
这是开始我的 QApplication
:
if __name__ == "__main__":
app = QtGui.QApplication(sys.argv)
finalForm = MainWindow()
finalForm.show()
sys.exit(app.exec_())
我在按下按钮时调用函数 rv,尽管进度条一直在正常更新,但 window 一段时间后开始变得无响应。我不明白在什么时候我可以使用 app.processEvents()
告诉我的 QApplication 在单独的线程或后台运行进程。
问题是,这并不是说您的应用被冻结,而是 Windows 认为应用被冻结是因为它忽略了事件(鼠标悬停、单击等),所以 Windows,以它的智慧,给你这样的对话。
您需要在 show() 之后关闭线程,然后 运行 processEvents 函数,显然只有在线程完成后才调用 sys.exit。
由于您似乎没有使用线程,可能只需要在更新进度条后调用 processEvents
,如下所示:
self.prog_QProgressBar.setValue(progressInt)
QtGui.qApp.processEvents()
但是,此方法的有效性可能取决于该过程产生输出所需的时间。 processEvents
调用所做的只是立即处理当前在应用程序事件队列中的任何未决事件(例如小部件绘制、鼠标单击等)。在这些调用之间,GUI 将继续冻结(即执行代码不是 运行 在单独的线程中或在后台,正如您所建议的那样)。因此,这种技术可以使 GUI 保持响应的程度取决于 processEvents
在 rv()
方法中的调用频率。