如何向QTableWidget添加数千条数据时不冻结窗口
核心问题原因
- 你当前的同步循环会完全阻塞Qt主事件循环,所有界面更新、用户交互事件都无法被处理,自然会出现窗口无响应
- QTableWidget默认每次插入行、设置单元格控件的操作都会触发即时重绘,数千次重绘叠加会放大耗时
- 你之前了解的QThread方案没用是对的,Qt所有界面相关操作都必须在主线程执行,仅把数据准备逻辑放到子线程无法解决问题,耗时大头本身就是界面控件创建和插入操作
可行实现方案(满足不冻结+逐行显示效果)
用QTimer分批插入行,每批插入少量行(可自定义每批数量,比如每次插10~20行),插入完成后主动让出事件循环的执行权,保证主界面可以响应交互、同时渲染刚插入的行。同时在单批插入的过程中临时关闭表格更新,单批插入完成后再打开更新触发一次重绘,进一步降低冗余重绘开销。
优化后代码
import sys from time import time from PySide6.QtWidgets import QTableWidget, QPushButton, QHeaderView, QApplication, QMainWindow from PySide6.QtCore import QTimer class Window(QMainWindow): def __init__(self): super().__init__() self.setFixedSize(1600, 900) self.table = QTableWidget(self) self.table.setFixedSize(1600, 900) self.table.setColumnCount(5) for col in range(5): self.table.horizontalHeader().setSectionResizeMode(col, QHeaderView.Stretch) self.total_rows = 2000 self.current_inserted = 0 self.batch_size = 20 # 可自行调整,数值越大插入越快,界面流畅度越低 self.insert_timer = QTimer(self) self.insert_timer.timeout.connect(self.insert_batch) self.show() self.insert_timer.start(0) # 0延迟触发,只要事件循环空闲就执行下一批 def insert_batch(self): # 单批插入前关闭更新,避免重复重绘 self.table.setUpdatesEnabled(False) for _ in range(self.batch_size): if self.current_inserted >= self.total_rows: self.insert_timer.stop() self.table.setUpdatesEnabled(True) print(f"全部插入完成") return row = self.table.rowCount() self.table.insertRow(row) for col in range(5): item = QPushButton("filler") self.table.setCellWidget(row, col, item) self.current_inserted += 1 # 单批插入完成后打开更新,触发一次重绘 self.table.setUpdatesEnabled(True)
额外优化建议
- 如果不需要每个单元格都是独立交互控件,优先使用
QTableWidgetItem而不是setCellWidget,性能可以提升数倍 - 如果后续需要支持更多行数(超过1万行),建议放弃QTableWidget改用
QTableView+自定义Model的方案,利用Qt的MVC框架复用渲染控件,只渲染可视区域内的行,性能会有质的提升 - 可以根据设备性能动态调整
batch_size的数值,平衡插入速度和界面流畅度
内容的提问来源于stack exchange,提问作者Campion
相关产品推荐
相关产品推荐

