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
相关产品推荐
相关产品推荐

