PySide 线程和 http 下载
Posted
技术标签:
【中文标题】PySide 线程和 http 下载【英文标题】:PySide threading and http downloading 【发布时间】:2012-02-08 12:29:01 【问题描述】:我很难让这段代码正常工作!!!!当我逐步调试它时它运行良好,但是当我正常运行时它只是崩溃。最初我使用 QThread 来更新 ImagePreview 像素图,但在经历了一整天的崩溃和痛苦之后,我改变了方向。现在它可以工作了,在上述情况下使用调试器时,但否则我很难过。请帮我!这段代码有什么问题?我可以使用另一种方法吗?我正在尝试使用从 url 下载的图像不断更新图像预览。
import sys
import io
import urllib2
from PySide import QtCore, QtGui, QtNetwork
import time
class QDownloadBuffer(QtCore.QBuffer):
downloadFinished = QtCore.Signal()
def __init__(self):
super(QDownloadBuffer, self).__init__()
self.open(QtCore.QBuffer.ReadWrite)
self.url = QtCore.QUrl("http://www.google.com.au/images/srpr/logo3w.png")
self.manager = QtNetwork.QNetworkAccessManager()
self.request = QtNetwork.QNetworkRequest(self.url)
self.manager.finished.connect(self.onFinished)
def startDownload(self):
print("Starting Download --")
self.reply = self.manager.get(self.request)
self.reply.error[QtNetwork.QNetworkReply.NetworkError].connect(self.onError)
def onFinished(self):
print("Download Finished -- ")
print(self.write(self.reply.readAll()))
self.reply.close()
self.downloadFinished.emit()
def onError(self):
print("oh no there is an error -- ")
print(self.reply.error())
class ImagePreview(QtGui.QWidget):
def __init__(self, parent=None):
super(ImagePreview, self).__init__(parent)
self.setMinimumSize(50, 50)
self.text = None
self.pixmap = None
self.dl_n = 0
def paintEvent(self, paintEvent):
painter = QtGui.QPainter(self)
if(self.pixmap):
painter.drawPixmap(0, 0, self.pixmap)
if(self.text):
painter.setPen(QtCore.Qt.blue)
painter.setFont(QtGui.QFont("Arial", 30))
painter.drawText(self.rect(), QtCore.Qt.AlignCenter, self.text)
def startDownload(self):
self.setText(str(self.dl_n))
self.dl_n += 1
print("Starting Download 0".format(self.dl_n))
self.db = QDownloadBuffer()
self.connect(self.db, QtCore.SIGNAL("downloadFinished()"), self, QtCore.SLOT("ondownloadFinished()"))
self.db.startDownload()
def ondownloadFinished(self):
self.paintImage()
print("download finished?")
self.db.close()
self.startDownload()
def paintImage(self):
print("Painting")
pixmap = QtGui.QPixmap()
pixmap.loadFromData(self.db.data())
self.setPixmap(pixmap)
def setPixmap(self, pixmap):
self.pixmap = pixmap
self.setMinimumSize(pixmap.width(), pixmap.height())
self.update()
def setText(self, text):
self.text = text
self.update()
class MainWindow(QtGui.QWidget):
def __init__(self):
super(MainWindow, self).__init__()
self.imagepreview = ImagePreview()
self.button = QtGui.QPushButton("Start")
self.button.clicked.connect(self.imagepreview.startDownload)
layout = QtGui.QVBoxLayout()
layout.addWidget(self.button)
layout.addWidget(self.imagepreview)
self.setLayout(layout)
if __name__ == "__main__":
import sys
try:
app = QtGui.QApplication(sys.argv)
except RuntimeError:
pass
mainwindow = MainWindow()
mainwindow.show()
sys.exit(app.exec_())
【问题讨论】:
【参考方案1】:我认为问题在于您正在从插槽(信号处理程序)调用self.startDownload()
。因此,您不会将控制权返回给 Qt 主循环(或类似的东西)。正确的方法是将其称为延迟事件,例如通过QTimer.singleShot
调用它:
def ondownloadFinished(self):
self.paintImage()
print("download finished?")
self.db.close()
QtCore.QTimer.singleShot(0, self.startDownload)
请注意,singleShot
与 msec
设置为 0:
QtCore.QTimer.singleShot(0, self.startDownload)
等同于:
QtCore.QMetaObject.invokeMethod(self, 'startDownload', QtCore.Qt.QueuedConnection)
(source, related question)
【讨论】:
只是一个简单的问题,您认为对这样的操作使用单独的线程是否更明智?我已经非常努力地尝试使用线程来实现它,但没有运气,但如果值得的话,我会在掌握这些新知识的情况下再试一次。 @kellpossible,你也可以用线程来做。例如pastebin.com/b4MD5jKh。但我不知道在你的情况下什么更好。 你太棒了。非常感谢,我真的在互联网上苦苦挣扎,寻找一个适合我情况的线程的好例子,但是你自己做了一个!以上是关于PySide 线程和 http 下载的主要内容,如果未能解决你的问题,请参考以下文章
PySide / PyQtGraph 访问主 Qt 事件线程
PySide2 和 Matplotlib:如何让 MatPlotLib 在单独的进程中运行? ..因为它不能在单独的线程中运行