2

I have my own table model subclassed from QAbstractTableModel. It is installed on my view (subclassed from QTableView). Inside the view, I'm using a delegate class (subclassed from QItemDelegate) for editing items.

I want to set up the following behaviour: when I finish editing data using my delegate, the next item in the model (the item in the next row and in the same column) should become editable.

Documentation says that it is provided by QAbstractItemDelegate::EditNextItem hint which is sent in closeEditor() signal. But by default this signal is sent with QAbstractItemDelegate::NoHint parameter. The problem is that I don't have to call this signal explicitly while reimplementing basic QItemDelegate virtual functions, such as setModelData() for example.

Documentation also says that this signal is sent by interior event filter which is installed on item delegate while calling QAbstractItemDelegate() constructor.

How could I provide my own EndEditHint in closeEditor() signal?

Toby Speight
  • 27,591
  • 48
  • 66
  • 103
DKurulyuk
  • 71
  • 4

1 Answers1

1

When you finish your editing, a delegate sends the closeEditor() signal with the SubmitModelCache hint. You have to keep this behavior in order to have your model properly updated.

To immediately open editor in the next cell after committing data from the previous editing you could reimplement the QItemDelegate::eventFilter() but I find a lot more easier just to reimplement the QAbstractItemView::closeEditor() method:

void CMyTableView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
{
    QTableView::closeEditor(editor, hint);

    QModelIndex index = moveCursor(MoveNext, Qt::NoModifier);
    if (!index.isValid()) 
        return;

    QPersistentModelIndex persistent(index);
    selectionModel()->setCurrentIndex(persistent, flags);

    // currentChanged signal would have already started editing
    if (index.flags() & Qt::ItemIsEditable && (!(editTriggers() & QAbstractItemView::CurrentChanged)))
        edit(persistent);
}

Even easier solution would be (I am not sure about it but it's definitely worth a try):

void CMyTableView::closeEditor(QWidget *editor, QAbstractItemDelegate::EndEditHint hint)
{
    QTableView::closeEditor(editor, hint);
    QTableView::closeEditor(nullptr, QAbstractItemDelegate::EditNextItem);       
}

The moveCursor() method returns an index of the next column and same row. If you want to change this behavior, reimplement it:

QModelIndex CMyTableView::moveCursor(CursorAction action, Qt::KeyboardModifiers modifiers)
{
    if (action == QAbstractItemView::MoveNext)
        action = QAbstractItemView::MoveDown;
    else if (action == QAbstractItemView::MovePrevious)
             action = QAbstractItemView::MoveUp;

    // Next row, same column.
    return QTableView::moveCursor(action, modifiers);
}

And by the way: When you press a Tab key, the default QTableView behavior is that the current editor is closed, data saved and next cell is edited.
So, maybe the only thing you have to do is just reimplement the QTableView::moveCursor() method.

Tomas
  • 2,170
  • 10
  • 14