繁体   English   中英

后台工作人员填充 QListView 缩略图

[英]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.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM