Skip to content
  • Categories
  • Recent
  • Tags
  • Popular
  • Users
  • Groups
  • Search
  • Get Qt Extensions
  • Unsolved
Collapse
Brand Logo
  1. Home
  2. Qt Development
  3. General and Desktop
  4. QCompleter with a model where first item is disabled breaks keyboard navigation
Forum Updated to NodeBB v4.3 + New Features

QCompleter with a model where first item is disabled breaks keyboard navigation

Scheduled Pinned Locked Moved Solved General and Desktop
4 Posts 2 Posters 307 Views
  • 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.
  • R Offline
    R Offline
    riplin
    wrote on last edited by
    #1

    Hi folks,

    I'm trying to create categorized items in a QCompleter list, where some items are headings that shouldn't be selectable by the user.

    When setting any item in the model that's hooked up to the QCompleter as disabled / unselectable other than the first one, this works fine. But when setting the first item as disabled / unselectable, keyboard navigation is broken. I can no longer up/down with the cursor keys to select an item.

    I tried hooking up event filters to look at the key events of the QLineEdit, the QCompleter and the QListView to see where the down key is processed, but when the first item is disabled, none of these see a down key event.

    1 Reply Last reply
    0
    • C Offline
      C Offline
      ChrisW67
      wrote on last edited by
      #2

      What form is the model? A list or a tree?
      Can you post a self-contained example that demonstrates the problem?

      1 Reply Last reply
      0
      • R Offline
        R Offline
        riplin
        wrote on last edited by
        #3

        In the createEditor method I do the following:

        auto* lineEdit = new QLineEdit(parent);
        auto* completerListView = new QListView(parent);
        auto* completer = new QCompleter(parent);
        completer->setPopup(completerListView);
        auto* completerModel = new MyCompleterModel(); //Inherits QAbstractItemModel
        completer->setModel(completerModel);
        completer->setCompletionMode(QCompleter::CompletionMode::UnfilteredPopupCompletion);
        completer->setModelSorting(QCompleter::ModelSorting::UnsortedModel);
        lineEdit->setCompleter(completer);
        
        return lineEdit;
        

        MyCompleterModel currently just has a list of hardcoded values that it returns, but the salient value in this case is in the flags method:

        Qt::ItemFlags
        MyCompleterModel::flags(const QModelIndex &index) const
        {
            auto f = QAbstractItemModel::flags(index);
            if (index.row() == 0)
                f &= ~Qt::ItemIsSelectable;
            return f;
        }
        
        1 Reply Last reply
        0
        • R Offline
          R Offline
          riplin
          wrote on last edited by riplin
          #4

          Someone on Reddit reminded me of the selection model and the following solves my problem:

          connect(completerListView->selectionModel(), &QItemSelectionModel::currentChanged, [completerModel, completerListView](const QModelIndex& current, const QModelIndex& previous)
          {
          
              int rowCount = completerModel->rowCount();
              if (rowCount == 0 || current.row() == -1) // Nothing to do.
                  return;
          
              int direction = current.row() == (previous.row() + 1) % rowCount ? 1 : -1;
          
              QModelIndex newIndex = current;
              while ((completerModel->flags(newIndex) & Qt::ItemIsSelectable) == 0)
              {
                  if (newIndex.row() == 0 && direction == -1)
                  {
                      newIndex = completerModel->index(-1, -1);
                      break;
                  }
                  newIndex = newIndex.sibling((newIndex.row() + direction) % rowCount, newIndex.column());
                  if (newIndex == current) // We've looped around and nothing could be selected. There's nothing we can do.
                      break;
              }
              if (newIndex != current)
              {
                  QTimer::singleShot(0, [completerListView, newIndex]()
                  {
                      completerListView->setCurrentIndex(newIndex);
                  });
              }
          
          });
          ;
          

          Edit: previous version I posted didn't handle upward movement. Also, QAbstractItemModel::flags returns NoItemFlags by default which was causing problems.

          Just to be clear, I do still believe that QCompleter is broken when it comes to disabled / unselectable items.

          1 Reply Last reply
          0

          • Login

          • Login or register to search.
          • First post
            Last post
          0
          • Categories
          • Recent
          • Tags
          • Popular
          • Users
          • Groups
          • Search
          • Get Qt Extensions
          • Unsolved