当模型是熊猫数据框时,使 QTableView 可编辑

Posted

技术标签:

【中文标题】当模型是熊猫数据框时,使 QTableView 可编辑【英文标题】:Make QTableView editable when model is pandas dataframe 【发布时间】:2016-12-16 20:55:02 【问题描述】:

在我的 gui 文件中,我按如下方式创建 QTableView(这是 Qt Designer 自动生成的部分):

self.pnl_results = QtGui.QTableView(self.tab_3)
font = QtGui.QFont()
font.setPointSize(7)
self.pnl_results.setFont(font)
self.pnl_results.setFrameShape(QtGui.QFrame.StyledPanel)
self.pnl_results.setFrameShadow(QtGui.QFrame.Sunken)
self.pnl_results.setEditTriggers(QtGui.QAbstractItemView.AllEditTriggers)
self.pnl_results.setShowGrid(True)
self.pnl_results.setSortingEnabled(True)
self.pnl_results.setCornerButtonEnabled(True)
self.pnl_results.setObjectName("pnl_results")

然后我定义一个模型,使我能够将 pandas 数据框链接到 QTableView:

class PandasModel(QtCore.QAbstractTableModel):
    """
    Class to populate a table view with a pandas dataframe
    """

    def __init__(self, data, parent=None):
        QtCore.QAbstractTableModel.__init__(self, parent)
        self._data = data

    def rowCount(self, parent=None):
        return len(self._data.values)

    def columnCount(self, parent=None):
        return self._data.columns.size

    def data(self, index, role=QtCore.Qt.DisplayRole):
        if index.isValid():
            if role == QtCore.Qt.DisplayRole:
                return str(self._data.values[index.row()][index.column()])
        return None

    def headerData(self, col, orientation, role):
        if orientation == QtCore.Qt.Horizontal and role == QtCore.Qt.DisplayRole:
            return self._data.columns[col]
        return None

    def setData(self, index, value, role):
        if not index.isValid():
            return False
        if role != QtCore.Qt.EditRole:
            return False
        row = index.row()
        if row < 0 or row >= len(self._data.values):
            return False
        column = index.column()
        if column < 0 or column >= self._data.columns.size:
            return False
        self._data.values[row][column] = value
        self.dataChanged.emit(index, index)
        return True

    def flags(self, index):
        flags = super(self.__class__,self).flags(index)
        flags |= QtCore.Qt.ItemIsEditable
        flags |= QtCore.Qt.ItemIsSelectable
        flags |= QtCore.Qt.ItemIsEnabled
        flags |= QtCore.Qt.ItemIsDragEnabled
        flags |= QtCore.Qt.ItemIsDropEnabled
        return flags

最后将我的 pandas 数据框 (df) 添加到模型中:

model = PandasModel(df)
self.ui.pnl_results.setModel(model)

这会在 QTableView 中正确显示我的 pandas 数据框。但是,由于某种原因,当我编辑文件时,返回到它们的原始值(并且一旦我编辑该字段,它开始为空)。如何使其可编辑,然后将结果写回熊猫数据框?

【问题讨论】:

【参考方案1】:

您的模型缺少setData 方法。 QtCore.QAbstractTableModel 的默认实现不执行任何操作并返回 False。您需要在模型中实现此方法以使其项目可编辑。如果df 是存储数据的实际容器,您只需在setData 方法中更改存储在容器中的项目的值。它可能看起来像这样:

def setData(self, index, value, role):
    if not index.isValid():
        return False
    if role != QtCore.Qt.EditRole:
        return False
    row = index.row()
    if row < 0 or row >= len(self._data.values):
        return False
    column = index.column()
    if column < 0 or column >= self._data.columns.size:
        return False
    self._data.values[row][column] = value
    self.dataChanged.emit(index, index)
    return True

还需要实现flags方法,返回一个包含QtCore.Qt.ItemIsEditable的值。

【讨论】:

您能举例说明 setData 方法的外观吗? 好的,添加示例实现。 我已将我的问题更改为最新版本,问题是编辑后的文件似乎没有传播到数据框,一旦我点击输入,值就会返回到原始值 看来下一个问题是特定于“熊猫数据框”的东西。在相关问题中,我找到了this 注释。试试这个,看看有没有帮助。 @Dimitry:链接中的模型似乎有效,只是不确定为什么它在每个字段中都有复选框。我怎样才能摆脱它们?有什么标志吗?

以上是关于当模型是熊猫数据框时,使 QTableView 可编辑的主要内容,如果未能解决你的问题,请参考以下文章

使用 QStandardItemModel 使 QTableView 的特定列只读

当我以下列方式修改熊猫数据框时会发生啥

使用熊猫数据框时出错

为啥在附加熊猫数据框时列顺序会发生变化?

如何在熊猫中迭代数据框时保留数据类型?

熊猫:连接数据框时如何聚合两个列表列