QTableView is a truly amazing Qt component. It allows us view and edit every custom table model we can imagine. However, the default way of editing is rather clunky, especially when compared with “industry standard” applications like Microsoft Excel or Google Sheets. Wouldn’t it be nice to edit the QTableView contents like in one of these applications?

Default behaviour

Let’s focus on the behaviour of Enter and Tab keys in QTableView. By default, the Tab key does exactly what we want:

  • It selects the cell to the right of the currently selected cell.
  • If the currently selected cell is being edited, the editing ends and the progress is saved.
  • If the currently selected cell is the last cell in the row, it selects the first cell in the next row.
Default Tab key behaviour
Default Tab key behaviour

However, pressing the Enter key does not do much. It only ends editing, without moving the selection down or right. It even does not enable editing of the currently selected cell.

Desired behaviour

What we want is to modify the behaviour of Enter key, so it behaves like in Microsoft Excel or Google Sheets:

  • If the selected cell is not being edited, start editing the cell.
  • If the selected cell is being edited, end the editing, save the value and select the cell below.
Enter key behaviour in Google Sheets
Enter key behaviour in Google Sheets

Solution : Subclass QTableView!

If we want to customize behaviour of a key, we need to override the QAbstractItemView::keyPressEvent() method. Once we override it, we are in full control of what happens when the given key is pressed. We can e.g. set the left arrow to act like the right arrow, we can modify the Delete key so it deletes an entire row, or (you guessed it right) we can modify the Enter key to make it behave like we specified above.


void keyPressEvent(QKeyEvent *pEvent) override
{
    if (pEvent->key() == Qt::Key_Return)
    {
        // we captured the Enter key press, now we need to move to the next row
        qint32 nNextRow = currentIndex().row() + 1;
        if (nNextRow + 1 > model()->rowCount(currentIndex()))
        {
            // we are all the way down, we can't go any further
            nNextRow = nNextRow - 1;
        }
       
        if (state() == QAbstractItemView::EditingState)
        {
            // if we are editing, confirm and move to the row below
            QModelIndex oNextIndex = model()->index(nNextRow, currentIndex().column());
            setCurrentIndex(oNextIndex);
            selectionModel()->select(oNextIndex, QItemSelectionModel::ClearAndSelect);
        }
        else
        {
            // if we're not editing, start editing
            edit(currentIndex());
        }
    }
    else
    {
        // any other key was pressed, inform base class
        QAbstractItemView::keyPressEvent(pEvent);
    }
}

The result

You can download the result here. After compiling and running, it shall look like this:

QTableview - The subclassed view's Enter key behaviour
The subclassed view’s Enter key behaviour

So there you have it! In the end, it was quite easy, wasn’t it? :-)

If you find an easier solution or have a question, see you in the comments!