在线程中创建QPixmaps

2024-09-30 00:41:59 发布

您现在位置:Python中文网/ 问答频道 /正文

我有一个问题,我试图加载大量的png图像,然后使用PyQt显示主题。我目前的工作流程是使用多处理器池来映射一个函数,该函数用“rb”值打开每个文件,然后将每个文件的字节读入一个统一的列表中。最后,父进程通过调用QPixmap对象的fromImageData方法来显示图像。这个方法似乎工作得很好,但是每次切换图像(8K分辨率)时,重新绘制一个新的pixmap非常慢。在

我希望为每个图像创建一个pixmap并循环遍历pixmap,而不是在每一步都用一个新的图像来重新创建相同的pixmap,这可能会更快。为此,我尝试在多进程函数中创建一个pixmap,但是这是不允许的,因为线程中没有父QApp。在

我的问题是,有没有合适的方法来做这件事?我也想过用芹菜/红葡萄酒来做,但我看不出有什么不同。为每个图像创建一个新的pixmap并使用setPixmap切换它们是一个可行的选择,还是有更合适的方法来实现这一点?在


Tags: 文件对象方法函数图像主题列表字节
1条回答
网友
1楼 · 发布于 2024-09-30 00:41:59

您应该能够使用QThreadPool和一些QRunnable来包装加载pixmap的代码。比如:

from PyQt5 import QtCore, QtGui

class PixmapLoader(QtCore.QRunnable):
    def __init__(self, filename):
        super().__init__()
        self.filename = filename
    def run(self):
        # Load pixmap at filename 
        # ...
        # then emit in a signal
        loaded.emit(pixmap)

    loaded = QtCore.pyqtSignal(QtGui.QPixmap)

然后在主应用程序的某个地方,创建一个线程池,运行加载对象,并处理它们的信号。在

^{pr2}$

我没有尝试过这个,但是因为Qt正在处理线程,所以应该能够很好地利用多个线程。在

编辑

正如评论中所解释的,这行不通。我忘记了QRunnable没有继承QObject,而且{}不能在主线程之外创建。但是使用一个image loader对象,将其移动到一个或多个后台线程中,在其中加载一个QImage,然后将其发送到主线程供以后使用。下面是一些经过测试的代码,它们将执行基本操作,加载当前目录中的所有PNG文件。在

#!/usr/bin/env python3

import os

from PyQt5.QtCore import pyqtSignal, QObject, QThread
from PyQt5.QtGui import QImage
from PyQt5.QtWidgets import QApplication

class ImageLoader(QObject):
    loaded = pyqtSignal(str, QImage)

    def __init__(self, filename):
        super().__init__()
        self.filename = filename

    def on_load_signal(self):
        img = QImage(self.filename)
        self.loaded.emit(self.filename, img)   


class LoaderManager(QObject):
    request_img_load = pyqtSignal()

    def __init__(self):
        super().__init__()
        self.loaders = list(map(ImageLoader, 
                filter(lambda f: f.endswith('.png'), os.listdir())))
        self.bg_thread = QThread()

        for loader in self.loaders:
            self.request_img_load.connect(loader.on_load_signal)
            loader.loaded.connect(self.handle_img_loaded)
            loader.moveToThread(self.bg_thread)

        self.bg_thread.start()

    def __del__(self):
        self.bg_thread.quit()

    def load_all(self):
        self.request_img_load.emit()

    def handle_img_loaded(self, name, img):
        print('File {} of size {} loaded'.format(name, img.byteCount()))

if __name__ == '__main__':

    app = QApplication([])
    manager = LoaderManager()
    manager.load_all()

相关问题 更多 >

    热门问题