当模型为pandas数据框时,如何使QTableView可编辑

3
在我的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 dataframe与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数据框。然而,出现问题的是当我编辑字段后,它们会返回到原始值(并且一旦我编辑了该字段,它就会变为空)。我该如何使其可编辑,并将结果写回pandas数据框中?

2个回答

5

你的模型缺少 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方法应该长什么样子? - Nickpick
我已经修改了我的问题到最新版本,问题是编辑后的字段似乎没有传播到数据框中,一旦我按下回车键,值就会返回到原始值。 - Nickpick
看起来下一个问题是特定于那个“pandas dataframe”东西的。在相关的问题中,我找到了这个注释。尝试一下,看看是否有帮助。 - Dmitry
@Dimitry:链接中的模型似乎是有效的,只是不确定为什么每个字段都有复选框。我该如何摆脱它们?是否有相关标志可以设置? - Nickpick
请上传一个截图,展示你所观察到的内容。我不确定你指的是哪种复选框。 - Dmitry
显示剩余10条评论

0
    def setData(self, index, value, role=Qt.EditRole):
    if index.isValid():
        if role == Qt.EditRole:
            self._data.iat[index.row(),index.column()] = value
            self.dataChanged.emit(index, index)
            return True
    return False

self._data.values[row][column] = value

对我来说没有用,但改为使用iat就可以了。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接