Qt Forum

    • Login
    • Search
    • Categories
    • Recent
    • Tags
    • Popular
    • Users
    • Groups
    • Search
    • Unsolved

    Update: Forum Guidelines & Code of Conduct

    Unsolved Problem with pressing TAB key during QTableView cell edit

    General and Desktop
    qt4.8 qtableview qitemdelegate editor tab
    2
    4
    4196
    Loading More Posts
    • Oldest to Newest
    • Newest to Oldest
    • Most Votes
    Reply
    • Reply as topic
    Log in to reply
    This topic has been deleted. Only users with topic management privileges can see it.
    • B
      Ben35 last edited by Ben35

      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 ? :)

      raven-worx 1 Reply Last reply Reply Quote 0
      • raven-worx
        raven-worx Moderators @Ben35 last edited by raven-worx

        @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.

        --- SUPPORT REQUESTS VIA CHAT WILL BE IGNORED ---
        If you have a question please use the forum so others can benefit from the solution in the future

        1 Reply Last reply Reply Quote 1
        • B
          Ben35 last edited by

          Not sure how i can do this ...

          1 Reply Last reply Reply Quote 0
          • B
            Ben35 last edited by

            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);
            }
            
            1 Reply Last reply Reply Quote 1
            • First post
              Last post