You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

PyQt6中QPixmapCache异常:循环内可查缓存,循环外find返回None

QPixmapCache循环内可找到对象,循环外返回None的问题解决

问题描述

开发PyQt6图片序列播放控件时,将图片通过QPixmapCache.insert()存入缓存后,插入循环内调用QPixmapCache.find()能正常获取QPixmap对象,但循环外调用该方法却返回None,无法读取缓存内容。相关代码及运行输出如下:

原代码

import sys
from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QLabel
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap, QPixmapCache
from pathlib import Path

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.animating_label = QLabel('animation here')
        self.animating_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
        self.animating_label.pixmap().size().setWidth(200)
        self.animating_label.pixmap().size().setHeight(200)
        self.setCentralWidget(self.animating_label)

        parent_path = Path(__file__).parent
        self.images_path = parent_path / 'images/animation_set/'
        self.animating_label.setPixmap(QPixmap(self.images_path.__str__() + "/clock01.png"))

        self.pixmapcache_keys: [str] = []

        self.load_images()
        test = QPixmapCache.find("clock02")
        try:
            self.animating_label.setPixmap(test)
        except:
            if test == None:
                print("Failure: QPixMapCache.find() returned", test)

    def load_images(self):
        image_suffixes = ['.jpg', '.png', '.gif', '.bmp']
        imgs_found_count = 0
        for filepath in self.images_path.iterdir():
            if filepath.suffix in image_suffixes:
                imgs_found_count += 1
                cache_key = filepath.stem
                self.pixmapcache_keys.append(cache_key)

                if not QPixmapCache.find(cache_key):
                    pixmap = QPixmap(filepath.__str__())
                    QPixmapCache.insert(cache_key, pixmap)

                print("pixmap %s" % cache_key, QPixmapCache.find(cache_key))


        print(imgs_found_count, "image(s) found in animation_set directory.", len(self.pixmapcache_keys),
              "keys loaded into QPixmapCache")

app = QApplication(sys.argv)

window = MainWindow()
window.show()

# start Qt event loop
app.exec()

print("Script complete.")
sys.exit(1)

运行输出

pixmap clock04 <PyQt6.QtGui.QPixmap object at 0x101c84b30>
pixmap clock10 <PyQt6.QtGui.QPixmap object at 0x101c84970>
pixmap clock11 <PyQt6.QtGui.QPixmap object at 0x101c84b30>
pixmap clock05 <PyQt6.QtGui.QPixmap object at 0x101c84970>
...

24 image(s) found in animation_set directory. 24 keys loaded into QPixmapCache
Failure: QPixMapCache.find() returned None
Script complete.

原因分析

  1. 默认缓存容量不足:QPixmapCache默认缓存上限为10240KB(10MB),当插入图片总大小超过该限制时,缓存会自动淘汰最早存入的条目,导致循环外查找时目标图片已被移除。
  2. 无效的尺寸修改逻辑:self.animating_label.pixmap().size().setWidth(200)这类代码不会生效,因为QPixmap.size()返回的是QSize副本,修改副本无法改变原Pixmap的尺寸(非缓存失败直接原因)。
  3. 缓存判断逻辑不严谨:if not QPixmapCache.find(cache_key)虽能判断空Pixmap,但更规范的方式是通过isNull()方法确认Pixmap有效性。

解决方案

  1. 增大缓存容量:程序启动时调用QPixmapCache.setCacheLimit()设置足够大的缓存值,确保所有图片能存入缓存。
  2. 修正缓存判断逻辑:使用isNull()方法准确判断缓存中是否存在有效Pixmap。
  3. 修复Label尺寸设置:改用setFixedSize()直接设置Label显示尺寸,或对Pixmap缩放后再设置。

修改后的代码

import sys
from PyQt6.QtWidgets import (
    QApplication,
    QMainWindow,
    QLabel
)
from PyQt6.QtCore import Qt
from PyQt6.QtGui import QPixmap, QPixmapCache
from pathlib import Path

class MainWindow(QMainWindow):

    def __init__(self):
        super().__init__()
        self.animating_label = QLabel('animation here')
        self.animating_label.setAlignment(Qt.AlignmentFlag.AlignHCenter | Qt.AlignmentFlag.AlignVCenter)
        # 修正Label尺寸设置方式
        self.animating_label.setFixedSize(200, 200)
        self.setCentralWidget(self.animating_label)

        parent_path = Path(__file__).parent
        self.images_path = parent_path / 'images/animation_set/'
        self.animating_label.setPixmap(QPixmap(self.images_path / "clock01.png"))

        self.pixmapcache_keys = []

        self.load_images()
        test = QPixmapCache.find("clock02")
        if not test.isNull():
            self.animating_label.setPixmap(test)
        else:
            print("Failure: QPixMapCache.find() returned invalid pixmap")

    def load_images(self):
        image_suffixes = ['.jpg', '.png', '.gif', '.bmp']
        imgs_found_count = 0
        for filepath in self.images_path.iterdir():
            if filepath.suffix in image_suffixes:
                imgs_found_count += 1
                cache_key = filepath.stem
                self.pixmapcache_keys.append(cache_key)

                # 修正缓存存在性判断逻辑
                pixmap = QPixmapCache.find(cache_key)
                if pixmap.isNull():
                    pixmap = QPixmap(filepath)
                    QPixmapCache.insert(cache_key, pixmap)

                print(f"pixmap {cache_key}", QPixmapCache.find(cache_key))

        print(f"{imgs_found_count} image(s) found in animation_set directory. {len(self.pixmapcache_keys)} keys loaded into QPixmapCache")

if __name__ == "__main__":
    # 设置缓存容量为50MB(根据实际图片总大小调整)
    QPixmapCache.setCacheLimit(50 * 1024)
    app = QApplication(sys.argv)

    window = MainWindow()
    window.show()

    app.exec()

    print("Script complete.")
    sys.exit(0)

额外说明

  • 缓存容量需根据图片总大小调整,避免设置过大占用过多内存。
  • Path对象可直接与字符串拼接,无需调用__str__(),简化代码。
  • 测试缓存查找时,优先判断pixmap.isNull()而非是否为None,符合Qt API使用规范。

内容的提问来源于stack exchange,提问作者digitoxin

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.20 12:36:25