[英]Background worker populate QListView thumbnails
我有一个简单的 QListview 显示项目名称列表。 我想在下载后显示每个项目的缩略图。 我如何才能做到以下几点,因为我不熟悉使用后台工作人员之类的东西,但我不确定如何实现这一点。
这解释了我认为最好的方法......
使用覆盖 initStyleOption() 函数的自定义 QStyledItemDelegate。
检测缺少图标并发出异步请求以加载它。
同时,显示默认的空图标以便用户看到占位符
当下载图标的异步请求完成时,它会通知我的小部件更新项目图标。
当我创建我所有的 QStandardModelItems 时,我给他们一个自定义数据(自定义角色),其中包含每个项目的缩略图路径
import os import sys from PySide2 import QtCore, QtGui, QtWidgets try: # python 2 from urllib import urlretrieve from urllib2 import urlopen except Exception as e: # python 3 from urllib.request import urlretrieve, urlopen import time from urllib.parse import urlparse def getThumbnail(url, output): if os.path.exists(output): return output # # download 1 # # urlretrieve(url, output) # # return os.path.abspath(output) # download 2 response = urlopen(url, timeout=5000) f = open(output, "wb") try: f.write(response.read()) finally: f.close() return output class ExampleDialog(QtWidgets.QDialog): def __init__(self): super(ExampleDialog, self).__init__() self.itemModel = QtGui.QStandardItemModel() self.uiListView = QtWidgets.QListView() # self.uiListView.setViewMode(QtWidgets.QListView.IconMode) self.uiListView.setIconSize(QtCore.QSize(80, 60)) #set icon size self.uiListView.setGridSize(QtCore.QSize(90, 70)) #set icon grid display self.uiListView.setModel(self.itemModel) self.mainLayout = QtWidgets.QVBoxLayout(self) self.mainLayout.addWidget(self.uiListView) self.populateImages() def populateImages(self): root = os.path.join(os.getenv('APPDATA'), 'MyApp\\\\cache') if not os.path.exists(root): os.makedirs(root) print('IMAGES:', root) for x in range(20): url = 'https://picsum.photos/id/{}/80/60.jpg'.format(x) p = urlparse(url).path ext = os.path.splitext(p)[-1] output = os.path.join(root, '{}{}'.format(x, ext)) # get thumbnail getThumbnail(url, output) # Item item = QtGui.QStandardItem('{}'.format(x)) item.setData(QtGui.QPixmap(output), QtCore.Qt.DecorationRole) item.setData(output, QtCore.Qt.UserRole) self.itemModel.appendRow(item) if __name__ == '__main__': app = QtWidgets.QApplication(sys.argv) window = ExampleDialog() window.show() window.raise_() sys.exit(app.exec_())
您可以使用 QNetworkAccessManager 进行异步下载,而不是使用后台工作者。
from dataclasses import dataclass
from functools import cached_property
import sys
from PySide2 import QtCore, QtGui, QtWidgets, QtNetwork
@dataclass
class IconDownloader(QtCore.QObject):
url: QtCore.QUrl
index: QtCore.QPersistentModelIndex
_parent: QtCore.QObject = None
def __post_init__(self):
super().__init__()
self.setParent(self._parent)
@cached_property
def network_manager(self):
manager = QtNetwork.QNetworkAccessManager()
manager.finished.connect(self._handle_finished)
return manager
def start(self):
if self.index.isValid():
request = QtNetwork.QNetworkRequest(self.url)
request.setAttribute(
QtNetwork.QNetworkRequest.FollowRedirectsAttribute, True
)
self.network_manager.get(request)
def _handle_finished(self, reply):
if reply.error() == QtNetwork.QNetworkReply.NoError:
pixmap = QtGui.QPixmap()
ok = pixmap.loadFromData(reply.readAll())
if ok and self.index.isValid():
model = self.index.model()
model.setData(
QtCore.QModelIndex(self.index), pixmap, QtCore.Qt.DecorationRole
)
else:
print(reply.error(), reply.errorString())
reply.deleteLater()
self.deleteLater()
class ExampleDialog(QtWidgets.QDialog):
def __init__(self):
super(ExampleDialog, self).__init__()
self.itemModel = QtGui.QStandardItemModel()
self.uiListView = QtWidgets.QListView()
# self.uiListView.setViewMode(QtWidgets.QListView.IconMode)
self.uiListView.setIconSize(QtCore.QSize(80, 60)) # set icon size
self.uiListView.setGridSize(QtCore.QSize(90, 70)) # set icon grid display
self.uiListView.setModel(self.itemModel)
self.mainLayout = QtWidgets.QVBoxLayout(self)
self.mainLayout.addWidget(self.uiListView)
self.populateImages()
def populateImages(self):
for x in range(20):
url = f"https://picsum.photos/id/{x}/80/60.jpg"
item = QtGui.QStandardItem(f"x")
self.itemModel.appendRow(item)
downloader = IconDownloader(
QtCore.QUrl(url),
QtCore.QPersistentModelIndex(self.itemModel.indexFromItem(item)),
self,
)
downloader.start()
if __name__ == "__main__":
app = QtWidgets.QApplication(sys.argv)
window = ExampleDialog()
window.show()
window.raise_()
sys.exit(app.exec_())
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.