PySide 线程与 HTTP 下载
我在让这段代码正常工作上遇到了很多麻烦!!!当我一步一步调试的时候,它运行得很好,但正常运行时却总是崩溃。最开始我用的是QThread来更新ImagePreview的图像,但经过一天的崩溃和痛苦,我决定换个方法。现在在使用调试器的情况下,它能正常工作,但在其他情况下我就无从下手了。请帮帮我!这段代码有什么问题吗?我还有其他方法可以尝试吗?我想不断地用从网址下载的图片来更新图像预览。
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 个回答
8
我觉得问题出在你是从信号处理函数里调用了 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)