类型:Python,C++ & Qt4,创建时间:Jan. 17, 2012, 3:53 p.m.
标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/78/。
经常看到有人问在PyQt里面如何做长操作的时候更新GUI。我自己总结了几种方案,以及他 们的适用场合:
使用processEvents()
,适合每次处理时间短的情况,缺点是CPU占用可能很大:
for filename in os.listdir(pathToYourDir): doSomething() updateGui() qApp.processEvents()
用threading
,再用QMetaObject.invokeMethod()
向主线程传递跨线程的信息
class MyWindow(QMainWindow): @pyqtSlot(int) def updateProgress(self, value): self.lblProgress=str(value) def startProgress(self): #点击按钮的时候调用 t = ProcessorThread() t.start() class ProcessorThread(threading.Thread: def __init__(self, myWindow): threading.Thread.__init__(self) self.myWindow=myWindow def run(self): for filename in os.listdir(): doSomething() progress=29 #计算百分比 QMetaObject.invokeMethod(self.myWindow, "updateProgress", \ Qt.QueuedConnection, Q_ARG("int", progress)
此方案还有一个变种是使用跨线程的signal/slot(此方法还需要再参考QThread的文档,并非正规用法):
class MyWindow(QMainWindow): def __init__(self): self.processorThread=ProcessorThread() self.processorThread.progressUpdated.connect( \ self.updateProgress, Qt.QueuedConnection) @pyqtSlot(int) def updateProgress(self, value): self.lblProgress=str(value) class ProcessorThread(QThread): progressUpdated=pyqtSignal(int) def __init__(self): QThread.__init__(self) #没有parent参数 self.moveToThread(self) def run(self): for filename in os.listdir(): doSomething() progress=29 #计算百分比 self.progressUpdated.emit(progress)
用QProgressDialog
。有同步与异步两种方法。先看看同步。
buf=io.StringIO() progress=QProgressDialog(self.trUtf8("打开文件"), \ self.trUtf8("取消"), 0, f.size(), self) progress.setWindowModality(Qt.WindowModal) while not f.atEnd(): data=f.read(1024) text=data.decode(locale.getpreferredencoding()) buf.write(text) progress.setValue(f.pos()) if progress.wasCanceled(): return self.textEdit.setPlainText(buf.getvalue()) progress.setValue(f.size()) #100%的时候对话框自动关掉 progress.setParent(None) #清理资源
异步与第二种方案类似,但是采用signal/slot,而且不能是模态对话框。
把长的操作分为小的操作,适合每次处理都是异步的或者很复杂的情况
def __init__(self): self.itorator=self.fetchFile() self.timer=QTimer() self.timer.timeout.connect(self.processFile) self.timer.start(0) def fetchFile(self): for filename in os.listdir(pathToYourDir): yield filename def processFile(): try: filename=self.itorator.next() doSomething() updateGui() except StopIterator: self.timer.stop()
第四种方案不常用,但是当你的处理过程本身是异步的时候就会用到。第一、第二方案都不 错,优点是灵活。第三种方案也常见,优点是模态对话框阻止用户的其它操作,可以随时取 消。缺点是一个对话框挡在那里,相当地影响用户体验。
ps:这些代码不能直接运行。。。差不多懂就好,呵呵 再ps: 纯网络操作可以看一下我的 eventlet-pyqt
标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/78/。
zzhiyuan(Oct. 28, 2013, 9:14 p.m.)
等我做完成了,会来膜拜的,这东西找半天了。