Problem with pressing TAB key during QTableView cell edit



  • Hello all,

    PROBLEM

    I have a problem with the editing behaviour in a QTableView (i'm using Qt4.8). I have a QTableView in which i defined custom ItemDelegates with custom editors :

    • a custom widget A which inherits from QComboBox;
    • a custom widget B which inherits from QWidget and that contains a custom QDoubleSpinBox which inherits from QDoubleSpinBox;

    When i start edit a cell, a TAB keypress validates the current edition an the next cell becomes editable, which is the standard behaviour of QTableView. But with my custom editor widget B, when i press TAB during the edition, the focus is given to the next cell, but not in an editing mode. I don't have this problem with my custom widget A. I guess it is because this widget is composed with an internal spinbox.

    RESEARCH

    When a view calls createEditor function of delegate it also installs the delegate event filter to editor, so i guess that events on editor widgets are trapped and treated by the ItemDelegate :

    QWidget *QAbstractItemViewPrivate::editor(const QModelIndex &index,
                                              const QStyleOptionViewItem &options)
    {
        Q_Q(QAbstractItemView);
        QWidget *w = editorForIndex(index).widget.data();
        if (!w) {
            QAbstractItemDelegate *delegate = delegateForIndex(index);
            if (!delegate)
                return 0;
            w = delegate->createEditor(viewport, options, index);
            if (w) {
               w->installEventFilter(delegate);
        ......
    }
    

    With the widget A, which work perfectly, the keyPressEvent is treated in eventFilter method of my delegate :

    bool QStyledItemDelegate::eventFilter(QObject *object, QEvent *event)
    {
        QWidget *editor = qobject_cast<QWidget*>(object);
        if (!editor)
            return false;
        if (event->type() == QEvent::KeyPress) {
            switch (static_cast<QKeyEvent *>(event)->key()) {
            case Qt::Key_Tab:
                emit commitData(editor);
                emit closeEditor(editor, QAbstractItemDelegate::EditNextItem);
                return true;
            case Qt::Key_Backtab:
                emit commitData(editor);
                emit closeEditor(editor, QAbstractItemDelegate::EditPreviousItem);
    
    }
    

    With my widget B, this eventFilter method doesn't receive the KeyPressEvent which is actually treated by the QWidget::event(QEvent *event) method of my internal spinbox, which explains why it does a focusNextPrevChild instead of the closeEditor(editor, QAbstractItemDelegate::EditNextItem) that i would expect.

        case QEvent::KeyPress: {
            QKeyEvent *k = (QKeyEvent *)event;
            bool res = false;
            if (!(k->modifiers() & (Qt::ControlModifier | Qt::AltModifier))) {  //### Add MetaModifier?
                if (k->key() == Qt::Key_Backtab
                    || (k->key() == Qt::Key_Tab && (k->modifiers() & Qt::ShiftModifier)))
                    res = focusNextPrevChild(false);
                else if (k->key() == Qt::Key_Tab)
                    res = focusNextPrevChild(true);
                if (res)
                    break;
            }
    

    WHY ?

    I don't undestand how to resolve my problem, and why this keyPressEvent on my custom editor B is not treated by the delegate.

    In my custom editor widget B, i already did this :

    setFocusPolicy(Qt::WheelFocus);
    setFocusProxy(internalSpinbox);
    

    Anyone to save me ? :)


  • Moderators

    @Ben35 said:

    I don't undestand how to resolve my problem, and why this keyPressEvent on my custom editor B is not treated by the delegate.

    Because the item delegate is only installed as event filter on the widget you create as editor. But you need to filter events of a child widget.
    So when creating the editor widget you also need to make sure to install the item delegate (this) as event filter on the sub-editor-widget.



  • Not sure how i can do this ...



  • I think i've found a solution.

    First, i install an eventFilter in my custom editor widget B on the internal spinbox :

    internalSpinbox->installEventFilter(this);
    

    Then, i implement eventFilter to treat the events on the spinbox and duplicate them to the parent:

    bool AbstractRatioQuantitySpinbox::eventFilter(QObject *object, QEvent *event)
    {
        // cf http://stackoverflow.com/questions/12145522/why-pressing-of-tab-key-emits-only-qeventshortcutoverride-event
    
        if (event->type() == QEvent::KeyPress)
        {
            auto keyEvent = static_cast<QKeyEvent *>(event);
            if (keyEvent->key() == Qt::Key_Tab || keyEvent->key() == Qt::Key_Backtab) {
                QApplication::postEvent(
                    this, new QKeyEvent(keyEvent->type(), keyEvent->key(), keyEvent->modifiers()));
                return true;
            }
        }
        else if (event->type() == QEvent::FocusOut)
        {
            auto focusEvent = static_cast<QFocusEvent *>(event);
            QApplication::postEvent(this, new QFocusEvent(focusEvent->type(), focusEvent->reason()));
            return false;
        }
        return QWidget::eventFilter(object, event);
    }
    


Looks like your connection to Qt Forum was lost, please wait while we try to reconnect.