使用 QlistW 减少 RAM 使用 [关闭]

Posted

技术标签:

【中文标题】使用 QlistW 减少 RAM 使用 [关闭]【英文标题】:Reducing RAM usage with QlistW [closed] 【发布时间】:2022-01-22 19:18:49 【问题描述】:

我正在尝试以图标模式将 100,000 张图像加载到 QtWidgets.QListWidget 中。我知道这是大量照片,但我需要将它们全部加载,因为我正在制作一个图像查看应用程序。我正在通过QtGui.QIcon 加载所有图像,并且它需要存储所有这些图像的内存量很大。有谁知道如何以不同方式加载这些图像以减少我正在使用的 RAM 量或更改设置以减少 RAM?

import sys
import CustomWidgets as cw
import platform
from PyQt5 import QtCore, QtGui, QtWidgets
import os
import threading

# GUI FILE
from PhotosPage import Ui_MainWindow


class MainWindow(QtWidgets.QMainWindow):
    def __init__(self):
        QtWidgets.QMainWindow.__init__(self)
        self.ui = Ui_MainWindow()
        self.ui.setupUi(self)

        # connect tab Pages
        self.ui.PageButton_Photos.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.PhotosPage))
        self.ui.PageButton_Albums.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.AlbumsPage))
        self.ui.PageButton_People.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.PeoplePage))
        self.ui.PageButton_Groups.clicked.connect(lambda: self.ui.stackedWidget.setCurrentWidget(self.ui.GroupsPage))
        
        self.ui.AlbumInfoFrame.hide()
        
        # # Create album Cover - test
        # cw.AlbumCover(self)
        self.ui.listWidget.setIconSize(QtCore.QSize(128, 128))
        
        
        threading.Thread(target=self.loadImgs, name="Loading Images").start()

        self.show()
        
    def loadImgs(self):
        for i in os.listdir("D:/iPhone Pics"):
            item = QtWidgets.QListWidgetItem()
            photo = QtGui.QIcon("D:/iPhone Pics/"+i)
            item.setIcon(photo)
            self.ui.listWidget.addItem(item)
            
    
            
if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    window = MainWindow()
    sys.exit(app.exec_())

【问题讨论】:

如果您正在加载所有图像,程序显然需要全部大小。没有简单的解决方案,每个画廊类型的程序都有自己的处理方式,通过使用自定义缓存和优化来提高性能并避免过多的内存使用。您必须自己找到它,并且您可能需要使用带有 QListView 的自定义模型(它可以使用 QListWidget 来完成,但您需要仔细实现项目委托)。此外,您应该从不从另一个线程访问 UI 元素。 不必一次加载 100,000 张图像。图像查看器永远无法真正显示那么多图像,因为屏幕上没有足够的空间。您应该只加载足够的图像来填充显示区域(加上两边的几页),并删除该范围之外的所有先前加载的图像以限制内存使用。见this question 和this pyqt5 example。 【参考方案1】:

这里遇到了两个主要问题,首先,您尝试一次加载太多图像,这导致 CPU 速度变慢,其次您正在加载太大的文件。 -> 像素宽度和高度太大,而不是文件大小。

文件大小:

在我的例子中,我加载了 100,000 张分辨率为 4k 的图像,这是不必要的,因为我的图标只有 300 x 175。要解决此问题,您可以在 PIL 中打开图像并调整图像大小,然后将其带入到 Qt 以减少它使用的内存量。

image = Image.open("file Location")
image = image.resize((300,150),Image.ANTIALIAS)

# Turn PIL image to Qt Image
qImage = ImageQt(image)
pixmap = QtGui.QPixmap.fromImage(qImage)
Icon = QtGui.QIcon(pixmap)

或者您可以保存一个较小版本的文件,然后在使用更快的图标时加载它。

延迟加载:

在延迟加载方面,您可以使用如下所示的模型一次加载一行按钮。

import sys
from PyQt5 import QtGui, QtCore, QtWidgets
from PyQt5.QtCore import Qt
import os

class TestListModel(QtCore.QAbstractListModel):
    def __init__(self, parent=None):
        QtCore.QAbstractListModel.__init__(self, parent)
        self.list = parent
        self.fileList = os.listdir('P:/PhotoSorterInfo/MiniPhotos')

    def rowCount(self, index):
        return len(self.fileList)

    def data(self, index, role):
        if role == Qt.DisplayRole:
            if not self.list.indexWidget(index):
                button = QtWidgets.QPushButton()
                button.setIcon(QtGui.QIcon("P:/PhotoSorterInfo/MiniPhotos/" + self.fileList[index.row()]))
                button.setIconSize(QtCore.QSize(300, 300))
                self.list.setIndexWidget(index, button)
            return QtCore.QVariant()
        
        if role == Qt.SizeHintRole:
            return QtCore.QSize(300, 300)

    def columnCount(self, index):
        pass


def main():
    app = QtWidgets.QApplication(sys.argv)

    window = QtWidgets.QWidget()

    list = QtWidgets.QListView()
    model = TestListModel(list)

    list.setModel(model)
    list.setVerticalScrollMode(QtWidgets.QAbstractItemView.ScrollPerPixel)
    list.setViewMode(QtWidgets.QListView.IconMode)
    list.setSelectionMode(QtWidgets.QAbstractItemView.ExtendedSelection)
    
    list.setDragDropMode(QtWidgets.QAbstractItemView.DragDrop)
    list.setSelectionBehavior(QtWidgets.QAbstractItemView.SelectItems)
    list.setResizeMode(QtWidgets.QListView.Adjust)
    list.setViewMode(QtWidgets.QListView.IconMode)
    list.setObjectName("PhotosFrame")
    

    layout = QtWidgets.QVBoxLayout(window)
    layout.addWidget(list)

    window.setLayout(layout)
    window.show()

    sys.exit(app.exec_())


if __name__ == '__main__':
    main() 

【讨论】:

以上是关于使用 QlistW 减少 RAM 使用 [关闭]的主要内容,如果未能解决你的问题,请参考以下文章

单片机内程序运行的时候ram空间是如何分配的?

RAM是如何分配的? [关闭]

C ++读/写 - RamDisk vs RAM [关闭]

WPF 窗口不停止计时器/关闭并降低 RAM 使用率

减少NPM内存使用量

R中的关联规则没有足够的RAM [关闭]