【问题标题】:Threading in pyqt4pyqt4中的线程
【发布时间】:2011-07-27 22:32:15
【问题描述】:

在我的 GUI 中,我必须在两者之间下载很多东西。我使用 urllib 来做到这一点。问题当然会变成 GUI 冻结,直到下载所有内容。

我的代码如下所示

QtCore.QObject.connect( self.UI.commandLinkButton_2 , QtCore.SIGNAL("clicked()") , self.addStoryToHistory )

其中上述函数有下载代码。

在这之间没有什么比发送共享数据更重要的了,这个过程只涉及将数据下载到一个位置。

不冻结我的 GUI 的最简单方法是什么?我应该使用multiprocessing 还是QThreads

谁能给我一些链接....我不希望它很复杂所以如果有更简单的方法请指出....

非常感谢...

【问题讨论】:

    标签: python multithreading pyqt4


    【解决方案1】:

    这是我刚刚从几个月前我正在从事的项目中剥离的一个示例,它使用 PyQt 中的 http 示例作为基础。它将从 Riverbank 网站下载 SIP。

    它使用来自 QtNetwork 的 QHttp 而不是 urllib,并且进度条连接到它的 dataReadProgress 信号。这应该让您能够可靠地下载文件并拥有响应式 GUI。

    from PyQt4.QtCore import QUrl, QFileInfo, QFile, QIODevice
    from PyQt4.QtGui import QApplication, QDialog, QProgressBar, QLabel, QPushButton, QDialogButtonBox, \
                        QVBoxLayout, QMessageBox
    from PyQt4.QtNetwork import QHttp
    
    url_to_download = 'http://www.riverbankcomputing.co.uk/static/Downloads/sip4/sip-4.12.3.zip'
    
    class Downloader(QDialog):
        def __init__(self, parent=None):
            super(Downloader, self).__init__(parent)
    
            self.httpGetId = 0
            self.httpRequestAborted = False
            self.statusLabel = QLabel('Downloading %s' % url_to_download)
            self.closeButton = QPushButton("Close")
            self.closeButton.setAutoDefault(False)
            self.progressBar = QProgressBar()
    
            buttonBox = QDialogButtonBox()
            buttonBox.addButton(self.closeButton, QDialogButtonBox.RejectRole)
    
            self.http = QHttp(self)
            self.http.requestFinished.connect(self.httpRequestFinished)
            self.http.dataReadProgress.connect(self.updateDataReadProgress)
            self.http.responseHeaderReceived.connect(self.readResponseHeader)
            self.closeButton.clicked.connect(self.cancelDownload)
    
            mainLayout = QVBoxLayout()
            mainLayout.addWidget(self.statusLabel)
            mainLayout.addWidget(self.progressBar)
            mainLayout.addWidget(buttonBox)
            self.setLayout(mainLayout)
    
            self.setWindowTitle('Download Example')
            self.downloadFile()
    
        def downloadFile(self):
            url = QUrl(url_to_download)
            fileInfo = QFileInfo(url.path())
            fileName = fileInfo.fileName()
    
            if QFile.exists(fileName):
                QFile.remove(fileName)
    
            self.outFile = QFile(fileName)
            if not self.outFile.open(QIODevice.WriteOnly):
                QMessageBox.information(self, 'Error',
                        'Unable to save the file %s: %s.' % (fileName, self.outFile.errorString()))
                self.outFile = None
                return
    
            mode = QHttp.ConnectionModeHttp
            port = url.port()
            if port == -1:
                port = 0
            self.http.setHost(url.host(), mode, port)
            self.httpRequestAborted = False
    
            path = QUrl.toPercentEncoding(url.path(), "!$&'()*+,;=:@/")
            if path:
                path = str(path)
            else:
                path = '/'
    
            # Download the file.
            self.httpGetId = self.http.get(path, self.outFile)
    
        def cancelDownload(self):
            self.statusLabel.setText("Download canceled.")
            self.httpRequestAborted = True
            self.http.abort()
            self.close()
    
        def httpRequestFinished(self, requestId, error):
            if requestId != self.httpGetId:
                return
    
            if self.httpRequestAborted:
                if self.outFile is not None:
                    self.outFile.close()
                    self.outFile.remove()
                    self.outFile = None
                return
    
            self.outFile.close()
    
            if error:
                self.outFile.remove()
                QMessageBox.information(self, 'Error',
                        'Download failed: %s.' % self.http.errorString())
    
            self.statusLabel.setText('Done')       
    
        def readResponseHeader(self, responseHeader):
            # Check for genuine error conditions.
            if responseHeader.statusCode() not in (200, 300, 301, 302, 303, 307):
                QMessageBox.information(self, 'Error',
                        'Download failed: %s.' % responseHeader.reasonPhrase())
                self.httpRequestAborted = True
                self.http.abort()
    
        def updateDataReadProgress(self, bytesRead, totalBytes):
            if self.httpRequestAborted:
                return
            self.progressBar.setMaximum(totalBytes)
            self.progressBar.setValue(bytesRead)
    
    if __name__ == '__main__':
        import sys
        app = QApplication(sys.argv)
        downloader = Downloader()
        downloader.show()
        sys.exit(app.exec_())
    

    【讨论】:

    • 嘿,非常感谢....你能告诉我假设我想要批量下载,我如何在整个下载过程中使用相同的进度条?
    • 对不起,我错过了这条评论。我想说这取决于文件的数量和文件的大小;如果它们很小而且很多,则将进度条的最大值作为文件数,并在下载文件时将其移动。如果文件大小不同,为了更准确地显示,您需要在下载之前先获取所有文件的总大小,以便设置进度条。
    【解决方案2】:

    我建议您改用 QNetworkManager 并监控下载过程。

    查看其他问题: pyQT QNetworkManager and ProgressBars

    【讨论】:

      猜你喜欢
      • 2011-07-10
      • 2015-07-12
      • 1970-01-01
      • 2018-10-04
      • 2011-08-05
      • 1970-01-01
      • 2017-09-10
      • 1970-01-01
      • 2018-03-03
      相关资源
      最近更新 更多