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. QTreeView drop event & re-selecting dropped items

QTreeView drop event & re-selecting dropped items

Scheduled Pinned Locked Moved Unsolved General and Desktop
12 Posts 3 Posters 3.8k 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.
  • D Offline
    D Offline
    Dariusz
    wrote on last edited by
    #1

    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-worxR 1 Reply Last reply
    0
    • D Dariusz

      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-worxR Offline
      raven-worxR Offline
      raven-worx
      Moderators
      wrote on last edited by
      #2

      @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
      0
      • D Offline
        D Offline
        Dariusz
        wrote on last edited by Dariusz
        #3

        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-worxR 1 Reply Last reply
        0
        • D 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-worxR Offline
          raven-worxR Offline
          raven-worx
          Moderators
          wrote on last edited by
          #4

          @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
          0
          • D Offline
            D Offline
            Dariusz
            wrote on last edited by Dariusz
            #5

            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-worxR 1 Reply Last reply
            0
            • D 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-worxR Offline
              raven-worxR Offline
              raven-worx
              Moderators
              wrote on last edited by
              #6

              @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
              0
              • D Offline
                D Offline
                Dariusz
                wrote on last edited by Dariusz
                #7

                @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
                0
                • SGaistS Offline
                  SGaistS Offline
                  SGaist
                  Lifetime Qt Champion
                  wrote on last edited by
                  #8

                  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
                  0
                  • D Offline
                    D Offline
                    Dariusz
                    wrote on last edited by
                    #9

                    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-worxR 1 Reply Last reply
                    0
                    • D Dariusz

                      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-worxR Offline
                      raven-worxR Offline
                      raven-worx
                      Moderators
                      wrote on last edited by
                      #10

                      @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
                      2
                      • raven-worxR raven-worx

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

                        D Offline
                        D Offline
                        Dariusz
                        wrote on last edited by
                        #11

                        @raven-worx Hmm So I need to adjust:

                        dragEnterEvent, dragMoveEvent, dragLeaveEvent, dropEvent ? Give them either

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

                        raven-worxR 1 Reply Last reply
                        0
                        • D Dariusz

                          @raven-worx Hmm So I need to adjust:

                          dragEnterEvent, dragMoveEvent, dragLeaveEvent, dropEvent ? Give them either

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

                          raven-worxR Offline
                          raven-worxR Offline
                          raven-worx
                          Moderators
                          wrote on last edited by
                          #12

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

                          • Login

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