让我们说我有一个PyQt程序,它通过一个给定的目录,查找*JPEG
个图像,并在每次找到它时进行一些处理。根据所选目录的大小,这可能需要几秒到几分钟。
我想让我的用户更新状态 - 最好使用" x文件处理y文件" 。如果没有,通过设置progressbar.setRange(0,0)
的简单运行脉冲进度条也可以。
根据我的理解,为了防止我的GUI冻结,我需要一个处理图像的独立线程,以及每隔一段时间更新GUI的原始线程。
但我想知道我是否有可能在同一个帖子中同时做两件事?
答案 0 :(得分:3)
是的,您可以使用processEvents轻松完成此操作,single-shot timer是为了这个目的而提供的。
我已经使用这种技术来实现一个简单的文件查找对话框。您需要做的就是启动使用{{3}}处理文件的函数,然后定期在循环中调用processEvents
。这应该足以使用处理的文件数更新计数器,并允许用户在必要时取消该过程。
唯一真正的问题是决定拨打processEvents
的频率。您调用它的次数越多,GUI的响应速度就越快 - 但这会以大大减慢文件处理速度为代价。因此,您可能需要进行一些实验才能找到可接受的折衷方案。
<强>更新强>:
这是一个简单的演示,展示了如何构建代码:
import sys, time
from PyQt5 import QtWidgets, QtCore
class Window(QtWidgets.QWidget):
def __init__(self):
super().__init__()
self.button = QtWidgets.QPushButton('Start')
self.progress = QtWidgets.QLabel('0')
layout = QtWidgets.QVBoxLayout(self)
layout.addWidget(self.button)
layout.addWidget(self.progress)
self.button.clicked.connect(self.test)
self._stop = False
self._stopped = True
def test(self):
if self._stopped:
self._stop = False
self.progress.setText('0')
self.button.setText('Stop')
QtCore.QTimer.singleShot(1, self.process)
else:
self._stop = True
def process(self):
self._stopped = False
for index in range(1, 1000):
time.sleep(0.01)
self.progress.setText(str(index))
if not index % 20:
QtWidgets.qApp.processEvents(
QtCore.QEventLoop.AllEvents, 50)
if self._stop:
break
self._stopped = True
self.button.setText('Start')
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = Window()
window.show()
sys.exit(app.exec_())
答案 1 :(得分:0)
如果没有多线程,我无法实现你需要的东西,这是不可能的,因为gui只能在主线程中更新。以下是我使用多线程执行此操作的算法。
让我们说您的应用程序处理图像。然后有以下线程:
正在处理电脑上图像的线程。
def process(self):
self._status = "processing image 1"
....
def _update(self):
self.status_label.setText(self._status)
def start_processing(self, image_path):
# create thread for process and run it
# create thread for updating by using QtCore.QTimer()
# connect qtimer triggered signal to and `self._update()` slot
# connect image processing thread (use connect signal to any slot, in this example I'll stop timer after processing thread finishes)
@pyqtSlot()
def _stop_timer():
self._qtimer.stop()
self._qtimer = None
_update_thread.finished.connect(_stop_timer)
在pyqt5中,可以从一个嵌套线程(第一级)分配pyqtvariable。因此,您可以使用setter和getter使变量成为pyqt变量,并在setter中更新gui,或者考虑如何自己完成。
答案 2 :(得分:0)
您可以使用python threading
模块并在线程例程中发出信号。
这是一个有效的例子
from PyQt4 import QtGui, QtCore
import threading
import time
class MyWidget(QtGui.QWidget):
valueChanged = QtCore.pyqtSignal(int)
def __init__(self, parent=None):
super(MyWidget, self).__init__(parent)
self.computeButton = QtGui.QPushButton("Compute", self)
self.progressBar = QtGui.QProgressBar()
layout = QtGui.QVBoxLayout(self)
layout.addWidget(self.computeButton)
layout.addWidget(self.progressBar)
self.computeButton.clicked.connect(self.compute)
self.valueChanged.connect(self.progressBar.setValue)
def compute(self):
nbFiles = 10
self.progressBar.setRange(0, nbFiles)
def inner():
for i in range(1, nbFiles+1):
time.sleep(0.5) # Process Image
self.valueChanged.emit(i) # Notify progress
self.thread = threading.Thread(target = inner)
self.thread.start()
if __name__ == "__main__":
import sys
app = QtGui.QApplication(sys.argv)
widget = MyWidget()
widget.show()
sys.exit(app.exec_())