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

PySide2多线程加载图片界面卡顿,如何实现PySide6同款流畅效果?

问题:PySide2中多线程加载图片卡顿,无法逐步显示的解决办法

我编写了一段多线程加载图片的代码,在PySide6、PyQt5和PyQt6中能保持UI响应并逐步显示图片,但在PySide2里界面会卡顿,必须等所有图片加载完成后才会一起显示。原代码如下:

import glob
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtCore import QThread, QObject, Signal, Slot
import sys

dir_path = 'F:/img/'  # 图片目录 #  

class Worker(QObject):
    progress = Signal(QtGui.QImage)
    
    @Slot()
    def do_work(self):
           
        res = glob.glob(dir_path+'*.png')+glob.glob(dir_path+'*.jpg')
        for path in res:
            icon = QtGui.QImage(path)
            self.progress.emit(icon)

class Demo(QtWidgets.QWidget):

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)  
        self.setGeometry(500, 300, 900, 530)
        self.setWindowTitle('Demo')
        
        self.gridLayout = QtWidgets.QGridLayout(self)
        self.listWidget = QtWidgets.QListWidget()
        self.listWidget.setIconSize(QtCore.QSize(100, 100))
        self.listWidget.setGridSize(QtCore.QSize(120, 130))               
        self.listWidget.setDefaultDropAction(QtCore.Qt.MoveAction)                    
        self.listWidget.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.listWidget.setResizeMode(QtWidgets.QListView.Adjust)
        self.listWidget.setViewMode(QtWidgets.QListView.IconMode)
        self.listWidget.setMovement(QtWidgets.QListView.Static)
        self.listWidget.setUpdatesEnabled(True)

        self.worker = Worker()
        self.thread = QThread()

        self.worker.progress.connect(self.update_progress)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.do_work)

        self.thread.start()
        self.gridLayout.addWidget(self.listWidget)  
                
    def update_progress(self, img):
      pixmap = QtGui.QPixmap()
      pixmap.convertFromImage(img)
      icon = QtGui.QIcon()
      icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.Off)
      item = QtWidgets.QListWidgetItem()
      item.setIcon(icon)
      self.listWidget.addItem(item)

app = QtWidgets.QApplication(sys.argv)
ex = Demo()
ex.show()
sys.exit(app.exec_())

解决办法

1. 强制UI即时刷新

PySide2的QListWidget在批量添加项时,默认不会立即触发界面刷新。在update_progress方法末尾添加UI刷新操作,确保每添加一个图片就更新界面:

修改后的update_progress方法:

def update_progress(self, img):
    pixmap = QtGui.QPixmap()
    pixmap.convertFromImage(img)
    icon = QtGui.QIcon()
    icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.Off)
    item = QtWidgets.QListWidgetItem()
    item.setIcon(icon)
    self.listWidget.addItem(item)
    # 强制刷新列表控件
    self.listWidget.update()
    # 或者调用processEvents确保事件循环处理更新(二选一即可)
    # QtWidgets.QApplication.processEvents()

2. 显式指定信号队列连接策略

PySide2中信号槽的默认连接行为与新版本Qt绑定库有差异,显式设置Qt.QueuedConnection可以确保UI线程按顺序处理图片更新信号,避免信号积压导致卡顿:

修改信号连接代码:

self.worker.progress.connect(self.update_progress, QtCore.Qt.QueuedConnection)

3. 工作线程内预处理图片

在后台线程直接将图片缩放到目标显示尺寸(100x100),减少UI线程的计算压力,同时降低内存占用:

修改Worker类的do_work方法:

@Slot()
def do_work(self):
    res = glob.glob(dir_path+'*.png') + glob.glob(dir_path+'*.jpg')
    target_size = QtCore.QSize(100, 100)
    for path in res:
        img = QtGui.QImage(path)
        # 按比例平滑缩放图片到目标尺寸
        scaled_img = img.scaled(target_size, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
        self.progress.emit(scaled_img)

完整修改后的代码

import glob
from PySide2 import QtCore, QtWidgets, QtGui
from PySide2.QtCore import QThread, QObject, Signal, Slot
import sys

dir_path = 'F:/img/'  # 图片目录 #  

class Worker(QObject):
    progress = Signal(QtGui.QImage)
    
    @Slot()
    def do_work(self):
        res = glob.glob(dir_path+'*.png') + glob.glob(dir_path+'*.jpg')
        target_size = QtCore.QSize(100, 100)
        for path in res:
            img = QtGui.QImage(path)
            scaled_img = img.scaled(target_size, QtCore.Qt.KeepAspectRatio, QtCore.Qt.SmoothTransformation)
            self.progress.emit(scaled_img)

class Demo(QtWidgets.QWidget):

    def __init__(self, parent=None):
        QtWidgets.QWidget.__init__(self, parent)  
        self.setGeometry(500, 300, 900, 530)
        self.setWindowTitle('Demo')
        
        self.gridLayout = QtWidgets.QGridLayout(self)
        self.listWidget = QtWidgets.QListWidget()
        self.listWidget.setIconSize(QtCore.QSize(100, 100))
        self.listWidget.setGridSize(QtCore.QSize(120, 130))               
        self.listWidget.setDefaultDropAction(QtCore.Qt.MoveAction)                    
        self.listWidget.setFrameShape(QtWidgets.QFrame.NoFrame)
        self.listWidget.setResizeMode(QtWidgets.QListView.Adjust)
        self.listWidget.setViewMode(QtWidgets.QListView.IconMode)
        self.listWidget.setMovement(QtWidgets.QListView.Static)
        self.listWidget.setUpdatesEnabled(True)

        self.worker = Worker()
        self.thread = QThread()

        # 指定QueuedConnection确保信号按顺序处理
        self.worker.progress.connect(self.update_progress, QtCore.Qt.QueuedConnection)
        self.worker.moveToThread(self.thread)
        self.thread.started.connect(self.worker.do_work)

        self.thread.start()
        self.gridLayout.addWidget(self.listWidget)  
                
    def update_progress(self, img):
        pixmap = QtGui.QPixmap()
        pixmap.convertFromImage(img)
        icon = QtGui.QIcon()
        icon.addPixmap(pixmap, QtGui.QIcon.Normal, QtGui.QIcon.Off)
        item = QtWidgets.QListWidgetItem()
        item.setIcon(icon)
        self.listWidget.addItem(item)
        # 强制刷新列表
        self.listWidget.update()

app = QtWidgets.QApplication(sys.argv)
ex = Demo()
ex.show()
sys.exit(app.exec_())

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.10 17:53:12