Search code examples
pythonpyside2

QlistWidget icons - faster loading


I am populating a QlistWidget with icons and I notice there is a lag when the window is loading. I wondered if there is a way to generate half resolution icons, or some other way to speed up the window generation time?

texture_item = QtWidgets.QListWidgetItem(texture)
texture_pixmap = QtGui.QPixmap(image_path)
texture_icon = QtGui.QIcon()          
self.list_widget_left.setIconSize(QtCore.QSize(105,105))
texture_item.setFont(QtGui.QFont('SansSerif', 10))
texture_icon.addPixmap(texture_pixmap)
texture_item.setIcon(texture_icon)
self.list_widget_left.addItem(texture_item)
texture_item.setTextAlignment(Qt.AlignBottom)

Solution

  • There are several aspects that can generate the delay:

    • The images weigh a lot then the solution is to use less heavy icons
    • You have many images that iterate in the same loop, then a possible solution is to give a small delay so that the image is loaded little by little avoiding the visual delay that you indicate.
    import os
    from PySide2 import QtCore, QtGui, QtWidgets
    import shiboken2
    
    
    def for_loop_files(path, interval=100, extensions=(), parent=None, objectName=""):
        timer = QtCore.QTimer(parent=parent, singleShot=True, interval=interval)
        if objectName:
            timer.setObjectName(objectName)
        loop = QtCore.QEventLoop(timer)
        timer.timeout.connect(loop.quit)
        timer.destroyed.connect(loop.quit)
        for root, dirs, files in os.walk(path):
            for name in files:
                base, ext = os.path.splitext(name)
                if extensions:
                    if ext in extensions:
                        if shiboken2.isValid(timer):
                            timer.start()
                            loop.exec_()
                            yield os.path.join(root, name)
                else:
                    yield os.path.join(root, name)
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.list_widget = QtWidgets.QListWidget()
            self.list_widget.setViewMode(QtWidgets.QListView.IconMode)
            self.list_widget.setIconSize(QtCore.QSize(128, 128))
            self.list_widget.setResizeMode(QtWidgets.QListView.Adjust)
            self.list_widget.setFlow(QtWidgets.QListView.TopToBottom)
            self.setCentralWidget(self.list_widget)
            self.resize(640, 480)
            QtCore.QTimer.singleShot(0, self.load_icons)
    
        @QtCore.Slot()
        def load_icons(self):
            for path in for_loop_files(".", extensions=(".png", "jpg"), parent=self, objectName="icon_timer", interval=30):
                it = QtWidgets.QListWidgetItem()
                it.setIcon(QtGui.QIcon(path))
                self.list_widget.addItem(it)
    
        def closeEvent(self, event):
            timer = self.findChild(QtCore.QTimer, "icon_timer")
            if timer is not None:
                timer.deleteLater()
            super(MainWindow, self).closeEvent(event)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())
    
    from PySide2 import QtCore, QtGui, QtWidgets
    import shiboken2
    
    
    def for_loop_files(paths, interval=100, parent=None, objectName=""):
        timer = QtCore.QTimer(parent=parent, singleShot=True, interval=interval)
        if objectName:
            timer.setObjectName(objectName)
        loop = QtCore.QEventLoop(timer)
        timer.timeout.connect(loop.quit)
        timer.destroyed.connect(loop.quit)
        for path in paths:
            if shiboken2.isValid(timer):
                timer.start()
                loop.exec_()
                yield path
    
    
    class MainWindow(QtWidgets.QMainWindow):
        def __init__(self, parent=None):
            super(MainWindow, self).__init__(parent)
            self.list_widget = QtWidgets.QListWidget()
            self.list_widget.setViewMode(QtWidgets.QListView.IconMode)
            self.list_widget.setIconSize(QtCore.QSize(128, 128))
            self.list_widget.setResizeMode(QtWidgets.QListView.Adjust)
            self.list_widget.setFlow(QtWidgets.QListView.TopToBottom)
            self.setCentralWidget(self.list_widget)
            self.resize(640, 480)
            QtCore.QTimer.singleShot(0, self.load_icons)
    
        @QtCore.Slot()
        def load_icons(self):
            paths = ["icon1.png", "icon2.png", "icon3.png", "icon4.png"]
            for path in for_loop_files(paths, parent=self, objectName="icon_timer", interval=30):
                it = QtWidgets.QListWidgetItem()
                it.setIcon(QtGui.QIcon(path))
                self.list_widget.addItem(it)
    
        def closeEvent(self, event):
            timer = self.findChild(QtCore.QTimer, "icon_timer")
            timer.deleteLater()
            super(MainWindow, self).closeEvent(event)
    
    
    if __name__ == "__main__":
        import sys
    
        app = QtWidgets.QApplication(sys.argv)
        w = MainWindow()
        w.show()
        sys.exit(app.exec_())