在PyQt里面如何做长操作时同时更新GUI

http://hgoldfish.com/blogs/article/78/




类型:Python,C++ & Qt4,创建时间:一月 17, 2012, 3:53 p.m.

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/78/。

经常看到有人问在PyQt里面如何做长操作的时候更新GUI。我自己总结了几种方案,以及他 们的适用场合:

  1. 使用processEvents(),适合每次处理时间短的情况,缺点是CPU占用可能很大:

    for filename in os.listdir(pathToYourDir):
        doSomething()
        updateGui()
        qApp.processEvents()
    
  2. 用QThread,用QMetaObject.invokeMethod()向主线程传递跨线程的信息

    class MyWindow(QMainWindow):
        @pyqtSlot(int)
        def updateProgress(self, value):
            self.lblProgress=str(value)
    
    class ProcessorThread(QThread):
        def __init__(self, myWindow):
            QThread.__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:

    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)
    
  3. 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,而且不能是模态对话框。

  4. 把长的操作分为小的操作,适合每次处理都是异步的或者很复杂的情况

    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:这些代码不能直接运行。。。差不多懂就好,呵呵

标题无“转载”即原创文章,版权所有。转载请注明来源:http://hgoldfish.com/blogs/article/78/。


zzhiyuan(十月 28, 2013, 9:14 p.m.) 

等我做完成了,会来膜拜的,这东西找半天了。


  • 1
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值