我试图找出如何在PyQt Qlistview中正确完成异步图像加载。如何正确加载PyQt5中的图像?
我的主要部件由Qlistview
和QLineEdit
文本框组成。 我有一个演员的数据库,我使用QAbstractListModel
的子类进行查询。当在文本框中输入文本时,将查询数据库并使用结果填充模型。结果显示在Qlistview中。 (A对于每个演员结果包含演员名称和图像的路径。)
当结果集太大(大于50),加载图像的问题开始从磁盘采取收费和悬挂用户界面。我希望实现的行为是最初为所有结果加载一个占位符图像,然后在另一个线程中加载磁盘中的特定图像,并在加载时使用新加载的图像更新Qlistview项目。
为此,我创建了一个自定义QItemDelegate
类,它具有需要加载的所有图像的缓存。如果图像不在缓存中,则它会绘制占位符图像并向另一个线程发送信号,该线程将该图像加载并放入缓存中。
我的委托类:
class MyDelegate(QStyledItemDelegate):
t1 = pyqtSignal(str, str, dict)
def __init__(self, image_cache, loader_thread, parent=None):
super(MyDelegate, self).__init__(parent)
self.placeholder_image = QPixmap(PLACEHOLDER_IMAGE_PATH).scaled(200, 300)
self.image_cache = image_cache
self.loader_thread = loader_thread
self.t1.connect(self.loader_thread.insert_into_queue)
def paint(self, QPainter, QStyleOptionViewItem, QModelIndex):
rect = QStyleOptionViewItem.rect
actor_name = QModelIndex.data(Qt.DisplayRole)
actor_thumb = QModelIndex.data(Qt.UserRole)
pic_rect = QRect(rect.left(), rect.top(), 200, 300)
text_rect = QRect(rect.left(), rect.top() + 300, 200, 20)
try:
cached_thumb = self.image_cache[actor_name]
print("Got image: {} from cache".format(actor_name)
except KeyError as e:
self.t1.emit(actor_name, actor_thumb, self.image_cache)
cached_thumb = self.placeholder_image
print("Drawing placeholder image for {}".format(actor_name)
QPainter.drawPixmap(pic_rect, cached_thumb)
QPainter.drawText(text_rect, Qt.AlignCenter, actor_name)
if QStyleOptionViewItem.state & QStyle.State_Selected:
highlight_color = QStyleOptionViewItem.palette.highlight().color()
highlight_color.setAlpha(50)
highlight_brush = QBrush(highlight_color)
QPainter.fillRect(rect, highlight_brush)
def sizeHint(self, QStyleOptionViewItem, QModelIndex):
return QSize(200, 320)
LoaderThread:
class LoaderThread(QObject):
def __init__(self):
super(LoaderThread, self).__init__()
@pyqtSlot(str, str, dict)
def insert_into_queue(self, name, thumb_path, image_cache):
print("Got signal, loading image for {} from disk".format(name))
pixmap = QPixmap(thumb_path).scaled(200, 300)
image_cache[name] = pixmap
print("Image for {} inserted to cache".format(name))
主窗口__init__
方法的主要组成部分:
image_cache = {}
lt = loader_tread.LoaderThread()
self.thread = QThread()
lt.moveToThread(self.thread)
self.thread.start()
self.delegate = MyDelegate(image_cache, lt)
当THI s的方法似乎工作,因为图像正确加载,当MyDelegate中的多个调用self.t1.emit(actor_name, actor_thumb, self.image_cache)
进行时,用户界面挂起。
事实上,延迟是几乎相同的图像时,加载在同一个线程像这样到:
try:
cached_thumb = self.image_cache[actor_name]
print("Got image: {} from cache".format(QModelIndex.data(Qt.DisplayRole)))
except KeyError as e:
# self.t1.emit(actor_name, actor_thumb, self.image_cache)
pixmap = QPixmap(actor_thumb).scaled(200,300)
self.image_cache[actor_name] = pixmap
cached_thumb = self.image_cache[actor_name]
如果有人有什么我做错了,或约期望的行为怎能任何指针达到他们将受到好评。
P.S 我知道我可以限制数据库查询中的结果集,但这不是我想要做的。
你做了任何分析?渲染图像需要的时间肯定比加载图像要长得多。 – ekhumoro
@ekhumoro与从磁盘加载图像的时间相比,位于内存中的图像的渲染时间可以忽略不计。当所有图像都在缓存中并且滚动变得平滑时,这是显而易见的。当仅渲染占位符图像(取消从磁盘完全加载图像)并且滚动平滑时,这也是明显的。 – Curtwagner1984