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
相关产品推荐
相关产品推荐

