Qt Forum

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

    Unsolved QTreeView drop event & re-selecting dropped items

    General and Desktop
    3
    12
    2871
    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.
    • D
      Dariusz last edited by

      Hey !

      I hit a bit of a weird wall in my tree subclass system. I have subclassed all tree/abastractItemModel and I'm using custom class for my nodes - lets call them myNodes.
      In any case when I try to process my drag/drop events. I have subclassed my drop event to be as follow :

      void myTree::dropEvent(QDropEvent *event) {
          if (event->mimeData()->hasFormat(myFormat)) {
              processLocalDropEvent(event);
          }
          dropIndicatorRect = QRect();
          dragActive = false;
      }
      

      the processLocalDropEvent checks if drop area is valid and then sends drop event to qabstractitemmodel with my mimedata function, that function returns a list of my myNodes.

      Once I get the myNodes list from mime function I then pass it to re-selecting function but to my surprise nothing gets reselected.

      void icTree::setSelectionOnDroppedItems(std::vector<myNodes*> _droppedNodes) {
          qDebug() << "selection re-run on drop?";
          clearSelection();
          int dataSize = _droppedNodes.size();
          for (int x = 0; x < dataSize; ++x) {
              QModelIndex itemIndex = _droppedNodes[x]->index();
              qDebug() << itemIndex << itemIndex.parent().data(Qt::DisplayRole);
              //selectionModel()->select(itemIndex, QItemSelectionModel::Select | QItemSelectionModel::Rows);
              selectionModel()->select(QItemSelection(itemIndex, itemIndex), QItemSelectionModel::Select | QItemSelectionModel::Rows);
          }
      //// PS I just added this line as I was typing the post, yeah if I do this the selection is accurate, so QT must be doing some selections after the dropEvent function! Halp where/who is calling that function ?!
          QCoreApplication::processEvents();
          system("pause");
      }
      

      The debug appear to be printing correct node index as well as the parent appear to be also accurate. But for some reason, I end up with 1-2 items selected out of 15 dragged. Even if I disable this re-selection function, the same selection patterns are present. I'm lost, does QT run any other selection function after drop event?

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

        @Dariusz
        are you just moving indexes within your model?
        If so you are supposed to use QPersistentModelIndexes instead of storing QModelIndex, which are not valid anymore after the model has changed. Where QPersitentModelIndexes get updated upon model changes.

        --- 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 0
        • D
          Dariusz last edited by Dariusz

          Hey @raven-worx

          I don't use modelIndexes at all during my move. I just pass vector with pointers to myNodes directly. As you can see after I do the drop and items are in new location, I run void icTree::setSelectionOnDroppedItems(std::vector<myNodes*> _droppedNodes) {} which re-creartes QModelIndexes, As I said in the "//// PS" comment. the function selects everything correctly. But then QT runs something after dropEvent that messes up my selection. I cant track down what QT runs after event drop so I can stop that.

          There must be a function that gets executed after void myTree::dropEvent(QDropEvent *event) {} that does something with the selection.

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

            @Dariusz said in QTreeView drop event & re-selecting dropped items:

            I don't use modelIndexes at all during my move. I just pass vector with pointers to myNodes directly

            Then what does QModelIndex itemIndex = _droppedNodes[x]->index(); exactly do?

            --- 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 0
            • D
              Dariusz last edited by Dariusz

              It creates new QModelIndexes for items after they were dropped. Sorry, I probably should not say that I don't use QModelIndexes at all. I use them but I create them after the items were dropped so they are all valid and correct. When I run this command

                QCoreApplication::processEvents();
                  system("pause");
              

              I can see all my dragged items being selected = great, but after that QT somehow breaks selection. No idea why and where. :- (!

              PS I have recorded a gif with the function above(processEvents and pause to show the issue)
              https://pasteboard.co/HaOlUyz.gif

              PS2 it feels to me that when I EnterDropEvent, a selection state is somewhere stored, and after I finish drop, that selection state is being restored. But I cant figure out where.

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

                @Dariusz
                is setSelectionOnDroppedItems() still called from within dropEvent handler?

                I am personally not a big fan of QCoreApplication::processEvents(); since it can break up so much stuff inside Qt. And i never encountered a case where it was absolutely necessary.

                You can try to restore the selection after you let Qt getting finished with the drop event.

                QMetaObject::invokeMethod(this, &setSelectionOnDroppedItems, Qt::QueuedConnection ); // will be executed in the next event loop iteration
                

                --- 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 0
                • D
                  Dariusz last edited by Dariusz

                  @raven-worx
                  "is setSelectionOnDroppedItems() still called from within dropEvent handler?"

                  Its the last function being called so :

                  void myTree::dropEvent(QDropEvent *event) {
                      if (event->mimeData()->hasFormat(myFormat)) {
                          processLocalDropEvent(event);
                      }
                      dropIndicatorRect = QRect();
                      dragActive = false;
                  }
                  
                  void myTree:: processLocalDropEvent(QDropEvent *event){
                  //// There is a lot more here, like deciding on what to drop and so on, but basic version is as follow
                      _droppedNodes = model()->dropMyMimeItems(event->mime,row,index,etc)
                      stopAutoScroll();
                      setState(NoState);
                      viewport()->update(); // can remove it from here/ use later in selection function.
                      setSelectionOnDroppedItems(_droppedNodes );
                  }
                  
                  void myTree::setSelectionOnDroppedItems(std::vector<myNodes*> _droppedNodes) {
                      clearSelection();
                      int dataSize = _droppedNodes.size();
                      for (int x = 0; x < dataSize; ++x) {
                          QModelIndex itemIndex = _droppedNodes[x]->index();
                          selectionModel()->select(QItemSelection(itemIndex, itemIndex), QItemSelectionModel::Select | QItemSelectionModel::Rows);
                      }
                  }
                  

                  This is full routine as far as I can tell from dropEvent till end. Will try the QMetaObject::invokeMethod sounds promising! never used it before :O thanks!

                  Edit. IT WORKS! Amazing ! But Omg I feel so dirty using that method lol...

                  1 Reply Last reply Reply Quote 0
                  • SGaist
                    SGaist Lifetime Qt Champion last edited by

                    Hi,

                    Shouldn't you rather do that check in dragMoveEvent like described here ?

                    Interested in AI ? www.idiap.ch
                    Please read the Qt Code of Conduct - https://forum.qt.io/topic/113070/qt-code-of-conduct

                    1 Reply Last reply Reply Quote 0
                    • D
                      Dariusz last edited by

                      Hey @SGaist just got back to the issue again. So the re-selection is working using that

                      QMetaObject::invokeMethod(this, "setSelectionOnDroppedItems", Qt::QueuedConnection);
                      

                      But I noticed that it created another "issue" mainly when I then try to select some items after drop, QT uses old selected item for starting "selection" and selects all until the item I clicked on... I'm bit lost now with it. As I made sure(I probably failed here) I have emitted drop events/mouseRelease events and so on to keep as much as I can of native QT signals but I'm missing something. Any idea what could be wrong here?

                      Attached video : http://www.dariuszmakowski.com/2018_05_15_09_52_33.mp4

                      Thanks for help & your time :- )

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

                        @Dariusz
                        it seems like you are not accepting all events?!
                        So some of them get passed to the parent widget and this confuses the widget implementation.

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

                        D 1 Reply Last reply Reply Quote 2
                        • D
                          Dariusz @raven-worx last edited by

                          @raven-worx Hmm So I need to adjust:

                          dragEnterEvent, dragMoveEvent, dragLeaveEvent, dropEvent ? Give them either

                          event->acceptProposedAction() or event->ignore() ?

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

                            @Dariusz
                            if you react to those events , accept them. If not just pass them to the base class implementation.

                            --- 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
                            • First post
                              Last post