Сделайте QTableView редактируемым, когда модель представляет собой панду

В моем графическом файле я создаю 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 dataframe (df):

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

Это правильно отображает мой кадр данных панд в QTableView. Однако по какой-то причине, когда я редактирую поля, возвращаются их исходные значения (а также, когда я редактирую поле, оно начинается как пустое). Как я могу сделать его редактируемым, а затем записать результаты обратно в кадр данных pandas?

2 ответа

Решение

В вашей модели отсутствует метод 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,

          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[строка][столбец] = значение

у меня не сработало, но смена с помощью iat сработала

Другие вопросы по тегам