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

PyQt5 DataFrame表格整数列过滤崩溃问题解决方案咨询

解决PyQt5 DataFrame整数列过滤崩溃的方案

崩溃原因分析

当前代码崩溃的核心原因是:处理整数列时,valuesUnique返回的是整数类型值,直接传入QtWidgets.QAction(actionName, self)会触发类型错误——QAction的文本参数要求是字符串类型,而非整数。此外,默认的QSortFilterProxyModel正则匹配是基于字符串的,若直接用字符串匹配整数数据,还可能出现匹配逻辑不准确的问题。

具体修复步骤

1. 修复菜单选项的类型错误

在生成表头过滤菜单时,将所有唯一值转为字符串,避免整数直接传入QAction:

修改on_view_horizontalHeader_sectionClicked方法中的循环部分:

for actionNumber, actionName in enumerate(sorted(list(set(valuesUnique)))):
    if actionName == "":
        continue
    # 将actionName转为字符串,兼容整数/浮点数类型
    action_text = str(actionName)
    action = QtWidgets.QAction(action_text, self)
    self.signalMapper.setMapping(action, actionNumber)
    action.triggered.connect(self.signalMapper.map)
    self.menuValues.addAction(action)

2. 重写QSortFilterProxyModel实现类型感知过滤

默认的正则匹配对数值类型不够友好(比如字符串"1"会匹配包含"1"的所有数值),我们可以自定义ProxyModel,根据列的数据类型选择匹配方式:

class TypeAwareSortFilterProxyModel(QtCore.QSortFilterProxyModel):
    def __init__(self, parent=None):
        super().__init__(parent)
        self._filter_column_type = None

    def setFilterColumnType(self, dtype):
        self._filter_column_type = dtype
        self.invalidateFilter()

    def filterAcceptsRow(self, source_row, source_parent):
        if self._filter_column_type is None:
            return super().filterAcceptsRow(source_row, source_parent)
        
        index = self.sourceModel().index(source_row, self.filterKeyColumn(), source_parent)
        data_value = self.sourceModel()._df.iloc[source_row, self.filterKeyColumn()]
        filter_str = self.filterRegExp().pattern()

        try:
            if pd.api.types.is_integer_dtype(self._filter_column_type):
                # 整数列:将过滤字符串转为整数后精确匹配
                filter_val = int(filter_str)
                return data_value == filter_val
            elif pd.api.types.is_float_dtype(self._filter_column_type):
                # 浮点列:转为浮点数后匹配,添加精度容差
                filter_val = float(filter_str)
                return abs(data_value - filter_val) < 1e-6
            else:
                # 字符串列保持原正则匹配
                return super().filterAcceptsRow(source_row, source_parent)
        except (ValueError, TypeError):
            # 过滤字符串无法转为对应数值时,不匹配任何行
            return False

3. 更新过滤逻辑,传入列类型

在on_view_horizontalHeader_sectionClicked方法中,获取当前列的数据类型并传给自定义Proxy:

@QtCore.pyqtSlot(int)
def on_view_horizontalHeader_sectionClicked(self, logicalIndex):
    self.logicalIndex = logicalIndex
    # 获取当前列的数据类型
    col_dtype = self.model._df.iloc[:, self.logicalIndex].dtype
    self.proxy.setFilterColumnType(col_dtype)
    
    # 剩余原有代码不变...

4. 替换默认Proxy为自定义Proxy

在newWindow方法中,使用自定义的类型感知ProxyModel:

def newWindow(self, table):
    self.model = pandasModel(table)
    # 替换为自定义的类型感知Proxy
    self.proxy = TypeAwareSortFilterProxyModel(self)
    self.proxy.setSourceModel(self.model)
    self.view = QtWidgets.QTableView()
    self.view.setModel(self.proxy)
    self.view.resize(1500, 600)
    self.view.resizeColumnsToContents()
    self.horizontalHeader = self.view.horizontalHeader()
    self.horizontalHeader.sectionClicked.connect(self.on_view_horizontalHeader_sectionClicked)
    self.view.setSelectionMode(QtWidgets.QAbstractItemView.SingleSelection)
    self.view.show()

额外优化建议

  • 处理空值:在生成菜单选项时,可添加对NaN/空值的特殊处理,比如显示"空值"选项并单独匹配。
  • 性能优化:若DataFrame数据量极大,可提前缓存各列的唯一值,避免每次点击表头都重新计算。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.08.20 15:33:24