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

PyQt5中QTableWidget筛选函数filterdata报KeyError:1的问题

PyQt5 QTableWidget筛选功能KeyError问题修复

问题描述

参考PyQt4的QTableWidget筛选方案适配PyQt5时,执行filterdata函数抛出KeyError:1。点击第一列表头并勾选筛选选项后,self.keywords初始化正常,但循环到j=1时触发错误,与复选框是否勾选无关。

报错核心代码

def filterdata(self):
    columnsShow = dict([(i, True) for i in range(self.qPerformanceReport_table.rowCount())])

    for i in range(self.qPerformanceReport_table.rowCount()):
        for j in range(self.qPerformanceReport_table.columnCount()):
            item = self.qPerformanceReport_table.item(i, j)
            if self.keywords[j]:
                if item.text() not in self.keywords[j]:
                    columnsShow[i] = False
    for key, value in enumerate(columnsShow[:]):
        self.qPerformanceReport_table.setRowHidden(key, not value)

问题原因

  1. 字典键缺失:self.keywords在__init__中初始化时,表格尚未加载数据,columnCount()返回0,导致self.keywords是空字典。后续加载表格数据后未更新该字典,遍历列时j=1、j=2等键不存在,触发KeyError。
  2. 字典遍历逻辑错误:enumerate(columnsShow[:])写法错误,字典不支持切片操作,会导致遍历逻辑异常。
  3. 变量名笔误:refresh_performance_report中使用了未定义的df_agg1,实际应为df_agg。

修复步骤

1. 修正self.keywords初始化时机

将self.keywords的初始化移到表格数据加载完成后,确保键与列数匹配:

def refresh_performance_report(self):
    df_agg = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                           columns=['a', 'b', 'c'])
    nRows, nColumns = df_agg.shape
    self.qPerformanceReport_table.setColumnCount(nColumns)
    self.qPerformanceReport_table.setRowCount(nRows)

    self.qPerformanceReport_table.setHorizontalHeaderLabels(df_agg.columns)
    # 初始化/更新keywords字典
    self.keywords = {i: [] for i in range(nColumns)}

    for i in range(self.qPerformanceReport_table.rowCount()):
        for j in range(self.qPerformanceReport_table.columnCount()):
            # 修正变量名笔误
            self.qPerformanceReport_table.setItem(i, j, QtWidgets.QTableWidgetItem(str(df_agg.iloc[i, j])))

    for j in range(self.qPerformanceReport_table.columnCount()):
        self.qPerformanceReport_table.resizeColumnToContents(j)

2. 修复filterdata函数逻辑

def filterdata(self):
    # 初始化所有行显示状态为True
    columnsShow = {i: True for i in range(self.qPerformanceReport_table.rowCount())}

    for i in range(self.qPerformanceReport_table.rowCount()):
        for j in range(self.qPerformanceReport_table.columnCount()):
            item = self.qPerformanceReport_table.item(i, j)
            # 先检查j是否在keywords中,避免KeyError
            if j in self.keywords and self.keywords[j]:
                if item.text() not in self.keywords[j]:
                    columnsShow[i] = False
    # 正确遍历字典设置行隐藏状态
    for row_idx, show in columnsShow.items():
        self.qPerformanceReport_table.setRowHidden(row_idx, not show)

3. 初始化时设置空字典兜底

在__init__中先初始化空字典,避免提前调用函数时出错:

def __init__(self):
    super(MyQtApp, self).__init__()
    self.setupUi(self)

    self.qPerformanceReport_refresh.clicked.connect(self.refresh_performance_report)
    self.horizontalHeader=self.qPerformanceReport_table.horizontalHeader()
    self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
    # 初始化为空字典,后续加载数据时更新
    self.keywords = {}
    self.checkBoxs = []
    self.col = None

完整修复后代码

class MyQtApp(main.Ui_MainWindow, QtWidgets.QMainWindow):
    def __init__(self):
        super(MyQtApp, self).__init__()
        self.setupUi(self)

        self.qPerformanceReport_refresh.clicked.connect(self.refresh_performance_report)
        self.horizontalHeader=self.qPerformanceReport_table.horizontalHeader()
        self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
        self.keywords = {}
        self.checkBoxs = []
        self.col = None

    def refresh_performance_report(self):
        df_agg = pd.DataFrame(np.array([[1, 2, 3], [4, 5, 6], [7, 8, 9]]),
                                       columns=['a', 'b', 'c'])
        nRows, nColumns = df_agg.shape
        self.qPerformanceReport_table.setColumnCount(nColumns)
        self.qPerformanceReport_table.setRowCount(nRows)
    
        self.qPerformanceReport_table.setHorizontalHeaderLabels(df_agg.columns)
        # 更新keywords字典
        self.keywords = {i: [] for i in range(nColumns)}

        for i in range(self.qPerformanceReport_table.rowCount()):
            for j in range(self.qPerformanceReport_table.columnCount()):
                self.qPerformanceReport_table.setItem(i, j, QtWidgets.QTableWidgetItem(str(df_agg.iloc[i, j])))

        for j in range(self.qPerformanceReport_table.columnCount()):
            self.qPerformanceReport_table.resizeColumnToContents(j)

    def slotSelect(self, state):
        for checkbox in self.checkBoxs:
            checkbox.setChecked(Qt.Qt.Checked == state)

    def on_view_horizontalHeader_sectionClicked(self, index):
        self.menu = QtWidgets.QMenu(self)
        self.col = index

        data_unique = []
        self.checkBoxs = []

        checkBox = QtWidgets.QCheckBox("Select all", self.menu)
        checkableAction = QtWidgets.QWidgetAction(self.menu)
        checkableAction.setDefaultWidget(checkBox)
        self.menu.addAction(checkableAction)
        checkBox.setChecked(True)
        checkBox.stateChanged.connect(self.slotSelect)

        for i in range(self.qPerformanceReport_table.rowCount()):
            if not self.qPerformanceReport_table.isRowHidden(i):
                item = self.qPerformanceReport_table.item(i, index)
                if item.text() not in data_unique:
                    data_unique.append(item.text())
                    checkBox = QtWidgets.QCheckBox(item.text(), self.menu)
                    checkBox.setChecked(True)
                    checkableAction = QtWidgets.QWidgetAction(self.menu)
                    checkableAction.setDefaultWidget(checkBox)
                    self.menu.addAction(checkableAction)
                    self.checkBoxs.append(checkBox)

        btn = QtWidgets.QDialogButtonBox(QtWidgets.QDialogButtonBox.Ok | QtWidgets.QDialogButtonBox.Cancel, Qt.Qt.Horizontal, self.menu)
        btn.accepted.connect(self.menuClose)
        btn.rejected.connect(self.menu.close)
        checkableAction = QtWidgets.QWidgetAction(self.menu)
        checkableAction.setDefaultWidget(btn)
        self.menu.addAction(checkableAction)

        headerPos = self.qPerformanceReport_table.mapToGlobal(self.horizontalHeader.pos())
        posY = headerPos.y() + self.horizontalHeader.height()
        posX = headerPos.x() + self.horizontalHeader.sectionPosition(index)
        self.menu.exec_(QtCore.QPoint(posX, posY))

    def menuClose(self):
        if self.col not in self.keywords:
            self.keywords[self.col] = []
        self.keywords[self.col] = []
        for element in self.checkBoxs:
            if element.isChecked():
                self.keywords[self.col].append(element.text())
        self.filterdata()
        self.menu.close()

    def clearFilter(self):
        for i in range(self.qPerformanceReport_table.rowCount()):
            self.qPerformanceReport_table.setRowHidden(i, False)

    def filterdata(self):
        columnsShow = {i: True for i in range(self.qPerformanceReport_table.rowCount())}

        for i in range(self.qPerformanceReport_table.rowCount()):
            for j in range(self.qPerformanceReport_table.columnCount()):
                item = self.qPerformanceReport_table.item(i, j)
                if j in self.keywords and self.keywords[j]:
                    if item.text() not in self.keywords[j]:
                        columnsShow[i] = False
        for row_idx, show in columnsShow.items():
            self.qPerformanceReport_table.setRowHidden(row_idx, not show)

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.05 08:24:52