Qt Forum

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

    Call for Presentations - Qt World Summit

    Unsolved ListView - currentIndex cannot be set in delegate with Component.onCompleted

    QML and Qt Quick
    2
    4
    122
    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.
    • K
      Kuczmil last edited by

      Hello,

      I would like to understand the underlying reason for the following behavior. There is such an exemplary piece of code:

      import QtQuick 2.15
      import QtQuick.Window 2.15
      import QtQuick.Controls 2.15
      
      Window {
          visible: true
          width: 500
          height: 600
      
      
          ListModel {
              id: myModel
              ListElement {name: "Item";}
              ListElement {name: "Item";}
              ListElement {name: "Item";}
              ListElement {name: "Item";}
          }
      
          ListView {
              id: listView
              width: parent.width
              height: 0.7 * parent.height
              signal test()
      
              model: myModel
      
              delegate: Rectangle {
                  id: listDelegate
                  color: listView.currentIndex == index ?  "green" : "red"
                  height: 50
                  width: listView.width
      
                  Text {
                      id: listDelegateText
                      text: name
                      anchors.centerIn: parent
                      font.pointSize: 20
                  }
      
                  Component.onCompleted: {
                      # the part that is not working:
                      listView.currentIndex = 2
                  }
              }
          }
      }
      

      My expectation is that currentIndex should be set to 2. However, there is even no attempt to change the index. The problem is that:

      • other ListView properties can be changed form that part that is not working, so we clearly have access to the right reference
      • ListView currentIndex can be changed in any other place of the code
      • starting an outside Timer from onCompleted part, even with the interval set to 0, also allows for the currentIndex change

      Given that all, the natural expectation is that the code above should also work. But it is not a case. I have started digging into the source code of QML and the only thing I have found is the following code:
      qtdeclarative-dev/src/quick/items/qquickitemview.cpp

      FxViewItem *QQuickItemViewPrivate::createItem(int modelIndex, QQmlIncubator::IncubationMode incubationMode)
      {
          Q_Q(QQuickItemView);
      
          if (requestedIndex == modelIndex && incubationMode == QQmlIncubator::Asynchronous)
              return nullptr;
      
          for (int i=0; i<releasePendingTransition.count(); i++) {
              if (releasePendingTransition.at(i)->index == modelIndex
                      && !releasePendingTransition.at(i)->isPendingRemoval()) {
                  releasePendingTransition[i]->releaseAfterTransition = false;
                  return releasePendingTransition.takeAt(i);
              }
          }
      
          inRequest = true;
      
          QObject* object = model->object(modelIndex, incubationMode);
          QQuickItem *item = qmlobject_cast<QQuickItem*>(object);
      
          if (!item) {
              if (!object) {
                  if (requestedIndex == -1 && model->incubationStatus(modelIndex) == QQmlIncubator::Loading) {
                      // The reason we didn't receive an item is because it's incubating async. We keep track
                      // of this by assigning the index we're waiting for to 'requestedIndex'. This will e.g. let
                      // the view avoid unnecessary layout calls until the item has been loaded.
                      requestedIndex = modelIndex;
                  }
              } else {
                  model->release(object);
                  if (!delegateValidated) {
                      delegateValidated = true;
                      QObject* delegate = q->delegate();
                      qmlWarning(delegate ? delegate : q) << QQuickItemView::tr("Delegate must be of Item type");
                  }
              }
              inRequest = false;
              return nullptr;
          } else {
              item->setParentItem(q->contentItem());
              if (requestedIndex == modelIndex)
                  requestedIndex = -1;
              FxViewItem *viewItem = newViewItem(modelIndex, item);
              if (viewItem) {
                  viewItem->index = modelIndex;
                  // do other set up for the new item that should not happen
                  // until after bindings are evaluated
                  initializeViewItem(viewItem);
                  unrequestedItems.remove(item);
              }
              inRequest = false;
              return viewItem;
          }
      }
      

      and

      void QQuickItemView::setCurrentIndex(int index)
      {
          Q_D(QQuickItemView);
          if (d->inRequest)  // currently creating item
              return;
          d->currentIndexCleared = (index == -1);
      
          d->applyPendingChanges();
          if (index == d->currentIndex)
              return;
          if (isComponentComplete() && d->isValid()) {
              d->moveReason = QQuickItemViewPrivate::SetIndex;
              d->updateCurrent(index);
          } else if (d->currentIndex != index) {
              d->currentIndex = index;
              emit currentIndexChanged();
          }
      }
      

      There is that inRequest boolean variable that smells suspicously. It would mean that calling onCompleted inside the delegate does not actually mean that the creation is fully completed.

      Generally, the questions:

      1. Am I correct that inRequest variable prevents from changing currentIndex in the way shown on the first code snippet in this post?
      2. Isn't that a bug?
      KroMignon 1 Reply Last reply Reply Quote 0
      • KroMignon
        KroMignon @Kuczmil last edited by

        @Kuczmil I don't think I understand what you want to achieve with this code?

        Why do you want to set ListView.currentIndex in delegate Component.onCompleted.
        This looks very strange to me, can you explain what is the goal of this?

        It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

        1 Reply Last reply Reply Quote 0
        • K
          Kuczmil last edited by

          @KroMignon
          So, the origin of that question is the following issue raised on SO:
          https://stackoverflow.com/questions/63252698/in-listview-how-can-you-set-the-currentindex-or-currentitem-to-a-dynamically-cr#comment111851987_63252698

          I just started to wonder why it is not possible to change currentIndex inside delegate Component.onCompleted. What is the reason? The code I provided is as simple as possible just to expose the issue.

          KroMignon 1 Reply Last reply Reply Quote 0
          • KroMignon
            KroMignon @Kuczmil last edited by

            @Kuczmil said in ListView - currentIndex cannot be set in delegate with Component.onCompleted:

            I just started to wonder why it is not possible to change currentIndex inside delegate Component.onCompleted.

            For me this is a non sense, you really know when ListView will create/destroy a delegate instance.
            It could be because model has changed (item inserted / deleted) or View has been scrolled and item visibility changes.

            This is not the right place to do something like this.

            It is an old maxim of mine that when you have excluded the impossible, whatever remains, however improbable, must be the truth. (Sherlock Holmes)

            1 Reply Last reply Reply Quote 0
            • First post
              Last post