You need to enable JavaScript to run this app.
最新活动
大模型
产品
解决方案
定价
生态与合作
支持与服务
开发者
了解我们

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_())
关键修改点
  1. 开启多选模式:通过setSelectionModesetSelectionBehavior设置单元格多选,支持用户选择任意数量的可编辑单元格。
  2. 实时保存选中项:监听itemSelectionChanged信号,提前保存所有选中的可编辑单元格,避免编辑时选中状态丢失。
  3. 捕获回车键触发批量更新:重写keyPressEvent,在用户按下回车时获取输入值,批量更新所有保存的选中单元格,同时更新DataFrame数据。
  4. 避免信号循环:更新单元格时使用blockSignals(True),防止cellChanged信号重复触发导致的异常。

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

火山引擎 最新活动