如何定制QTableView列以展示与模型不同的内容?
解决方案:扩展现有PandasModel实现只读计算列
你不需要额外创建模型,也不用修改QTableView,直接在现有的PandasModel里扩展逻辑,就能动态生成只读的额外列,同时完全保留原DataFrame(Table1)的结构。
具体实现思路
核心是重写QAbstractTableModel的几个关键方法,让模型在返回数据时动态计算出绝对路径、文件大小这类临时数据,完全不用修改原DataFrame的存储内容:
- 调整列数统计,把新增的列算进去
- 为新增列设置表头文本
- 针对新增列动态计算并返回对应数据
- 标记新增列为只读,禁止编辑操作
完整代码示例
from PySide6.QtCore import QAbstractTableModel, Qt, QModelIndex import pandas as pd import os class PandasModel(QAbstractTableModel): """A model to interface a Qt view with pandas dataframe """ def __init__(self, dataframe: pd.DataFrame, root_path: str, parent=None): QAbstractTableModel.__init__(self, parent) self._dataframe = dataframe self._root_path = root_path # 文件所在根目录,根据实际场景传入 def rowCount(self, parent=QModelIndex()): return self._dataframe.shape[0] def columnCount(self, parent=QModelIndex()): # 原列数 + 新增的2列(绝对路径、文件大小) return self._dataframe.shape[1] + 2 def headerData(self, section, orientation, role=Qt.DisplayRole): if role == Qt.DisplayRole and orientation == Qt.Horizontal: if section < self._dataframe.shape[1]: return self._dataframe.columns[section] elif section == self._dataframe.shape[1]: return "abs path" elif section == self._dataframe.shape[1] + 1: return "size" return super().headerData(section, orientation, role) def data(self, index, role=Qt.DisplayRole): if not index.isValid(): return None row = index.row() col = index.column() if role == Qt.DisplayRole: # 返回原DataFrame的列数据 if col < self._dataframe.shape[1]: return str(self._dataframe.iloc[row, col]) # 计算并返回绝对路径 elif col == self._dataframe.shape[1]: filename = self._dataframe.iloc[row, 0] return os.path.abspath(os.path.join(self._root_path, filename)) # 计算并返回文件大小(转换为KB) elif col == self._dataframe.shape[1] + 1: filename = self._dataframe.iloc[row, 0] file_path = os.path.join(self._root_path, filename) if os.path.exists(file_path): size_kb = os.path.getsize(file_path) / 1024 return f"{round(size_kb, 2)}KB" else: return "文件不存在" return None def flags(self, index): # 新增列设置为只读 if index.column() >= self._dataframe.shape[1]: return Qt.ItemIsSelectable | Qt.ItemIsEnabled # 原列保持默认规则(如果需要原列也只读,直接返回上面的flags即可) return super().flags(index)
为什么不选其他方案?
- 不用定制QTableView:Qt的MVC架构中,视图只负责展示数据,把计算逻辑塞进视图会导致代码耦合度高,后续修改或扩展非常麻烦。
- 不用创建两个模型:双模型会带来数据同步问题——原DataFrame更新时,你需要手动同步第二个模型,容易出现数据不一致的情况,完全没必要。
内容的提问来源于stack exchange,提问作者Moeda Chaos
相关产品推荐
相关产品推荐

