Editing QTableView cells

Allowing users to update the data in a model view
Heads up! You've already completed this tutorial.

Villa wrote

I need advice on how to make a QTableView editable. I created a UI containing a QTableView and set it to be editable with double click. Now I am able to edit a number but as soon as I press Enter the number returns to the original value without updating the dataframe.

In the model views course we covered displaying tabular data in Qt5 ModelViews. We implemented the data() method to return our values to the view for display. Qt doesn't understand your data structure so can't display it without your help, and the same goes for writing the edited data back to the data structure.

Because of this, making a QTableView editable is handled on the model. To support editing you now need to implement a setData() method. This works like the data() method, but should accept an index & value and use these to update the dataframe data.

You also need to implement the flags() method to add the Qt.ItemIsEditable flag, making elements editable.

If you only want certain cells to be editable, you can decide when to apply the editable flag based on the index in the flags() method.

A full working example for PyQt5 is below, using a Pandas dataframe:

Create GUI Applications with Python & Qt5 by Martin Fitzpatrick — (PyQt5 Edition) The hands-on guide to making apps with Python — Over 10,000 copies sold!

More info Get the book

python
import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import Qt
import pandas as pd

class TableModel(QtCore.QAbstractTableModel):

    def __init__(self, data):
        super().__init__()
        self._data = data

    def data(self, index, role):
        if role == Qt.DisplayRole:
            value = self._data.iloc[index.row(), index.column()]
            return str(value)

    def rowCount(self, index):
        return self._data.shape[0]

    def columnCount(self, index):
        return self._data.shape[1]

    def flags(self, index):
        if not index.isValid():
            return Qt.ItemIsEnabled

        return super().flags(index) | Qt.ItemIsEditable  # add editable flag.

    def headerData(self, section, orientation, role):
        # section is the index of the column/row.
        if role == Qt.DisplayRole:
            if orientation == Qt.Horizontal:
                return str(self._data.columns[section])

            if orientation == Qt.Vertical:
                return str(self._data.index[section])

    def setData(self, index, value, role):
        if role == Qt.EditRole:
            # Set the value into the frame.
            self._data.iloc[index.row(), index.column()] = value
            return True

        return False

class MainWindow(QtWidgets.QMainWindow):

    def __init__(self):
        super().__init__()

        self.table = QtWidgets.QTableView()

        data = pd.DataFrame([
          [1, 9, 2],
          [1, 0, -1],
          [3, 5, 2],
          [3, 3, 2],
          [5, 8, 9],
        ], columns = ['A', 'B', 'C'], index=['Row 1', 'Row 2', 'Row 3', 'Row 4', 'Row 5'])

        self.model = TableModel(data)
        self.table.setModel(self.model)

        self.setCentralWidget(self.table)


app=QtWidgets.QApplication(sys.argv)
window=MainWindow()
window.show()
app.exec_()

The setData method should return True if the value was successfully updated, or False if not. If False is returned the value displayed will be reverted to the previous value.

Well done, you've finished this tutorial! Mark As Complete
[[ user.completed.length ]] completed [[ user.streak+1 ]] day streak

Editing QTableView cells was written by Martin Fitzpatrick .

Martin Fitzpatrick has been developing Python/Qt apps for 8 years. Building desktop applications to make data-analysis tools more user-friendly, Python was the obvious choice. Starting with Tk, later moving to wxWidgets and finally adopting PyQt.