PyQt5 QTableWidget选中项不全:批量单元格赋值失效问题
问题分析
当你在QTableWidget中编辑单元格时,控件会自动清除其他单元格的选中状态,导致cellChanged信号触发时,selectedItems()只能获取到当前正在编辑的单个单元格,无法实现批量修改。
解决方案
通过提前保存选中的单元格列表,并捕获回车键事件来触发批量更新,解决选中状态丢失的问题:
import pandas as pd from PyQt5.QtWidgets import (QDialog, QDialogButtonBox, QApplication, QVBoxLayout, QTableWidget, QTableWidgetItem, QLineEdit) from PyQt5.QtCore import Qt, pyqtSlot import sys class NewTable(QDialog): def __init__(self, lnew, parent=None): super().__init__(parent) self.setWindowTitle("Enter Info") self.resize(1280, 720) self.lnew = lnew self.dfnew = pd.DataFrame(data=lnew, columns=["NAME"]) self.dfnew.insert(1, "ADDRESS", None) self.dfnew.insert(2, "CITY", None) self.dfnew.insert(3, "STATE", None) self.dfnew.insert(4, "ZIP", None) self.result = None # 保存当前选中的可编辑单元格 self.selected_cells = [] vlayout = QVBoxLayout() self.parmtbl = QTableWidget() vlayout.addWidget(self.parmtbl) self.parmtbl.setColumnCount(len(self.dfnew.columns)) self.parmtbl.setRowCount(len(self.dfnew.index)) self.parmtbl.setHorizontalHeaderLabels(self.dfnew.columns.tolist()) # 开启单元格多选模式 self.parmtbl.setSelectionMode(QTableWidget.ExtendedSelection) self.parmtbl.setSelectionBehavior(QTableWidget.SelectItems) # 初始化表格数据 for index, row in self.dfnew.iterrows(): # NAME列设置为仅可选不可编辑 name_item = QTableWidgetItem(row["NAME"]) name_item.setFlags(Qt.ItemIsSelectable | Qt.ItemIsEnabled) self.parmtbl.setItem(index, 0, name_item) # 初始化其他可编辑列 for col in range(1, len(self.dfnew.columns)): cell_val = "" if pd.isna(self.dfnew.iloc[index, col]) else str(self.dfnew.iloc[index, col]) item = QTableWidgetItem(cell_val) self.parmtbl.setItem(index, col, item) # 监听选中变化,实时保存选中的可编辑单元格 self.parmtbl.itemSelectionChanged.connect(self.save_selected_cells) QBtn = QDialogButtonBox.Ok | QDialogButtonBox.Cancel self.buttonBox = QDialogButtonBox(QBtn) self.buttonBox.accepted.connect(self.accept) self.buttonBox.rejected.connect(self.reject) vlayout.addWidget(self.buttonBox) self.setLayout(vlayout) def save_selected_cells(self): # 过滤掉不可编辑的NAME列,只保存可编辑单元格 self.selected_cells = [item for item in self.parmtbl.selectedItems() if item.column() != 0] def keyPressEvent(self, event): # 捕获回车键事件,触发批量更新 if event.key() in (Qt.Key_Return, Qt.Key_Enter): # 获取当前编辑器的输入值 editor = self.parmtbl.cellWidget(self.parmtbl.currentRow(), self.parmtbl.currentColumn()) if isinstance(editor, QLineEdit): new_value = editor.text() self.parmtbl.blockSignals(True) # 将值批量应用到所有选中的单元格 for item in self.selected_cells: row = item.row() col = item.column() self.dfnew.iloc[row, col] = new_value item.setText(new_value) self.parmtbl.blockSignals(False) # 关闭编辑器,结束编辑状态 self.parmtbl.closePersistentEditor(self.parmtbl.currentItem()) event.accept() return # 其他事件交给父类处理 super().keyPressEvent(event) if __name__ == '__main__': lnew = ["John", "Paul", "George", "Ringo"] app = QApplication(sys.argv) ex = NewTable(lnew) ex.show() sys.exit(app.exec_())
关键修改点
- 开启多选模式:通过
setSelectionMode和setSelectionBehavior设置单元格多选,支持用户选择任意数量的可编辑单元格。 - 实时保存选中项:监听
itemSelectionChanged信号,提前保存所有选中的可编辑单元格,避免编辑时选中状态丢失。 - 捕获回车键触发批量更新:重写
keyPressEvent,在用户按下回车时获取输入值,批量更新所有保存的选中单元格,同时更新DataFrame数据。 - 避免信号循环:更新单元格时使用
blockSignals(True),防止cellChanged信号重复触发导致的异常。
内容的提问来源于stack exchange,提问作者Kes Perron




