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. Baffled by QListView drag-drop for reordering list
QtWS25 Last Chance

Baffled by QListView drag-drop for reordering list

Scheduled Pinned Locked Moved General and Desktop
7 Posts 4 Posters 9.2k 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
    dcortesi
    wrote on 11 Dec 2012, 23:54 last edited by
    #1

    I've read the docs repeatedly and read the numerous items in this forum that seem to be related, and am getting nowhere. Using PyQt4 on OSX10.6 I have implemented a basic list model including besides the data, setData, and flags methods also insertRows, removeRows, itemData and setItemData. flags() returns Qt.ItemIsEnabled | Qt.ItemIsSelectable | Qt.ItemIsEditable | Qt.ItemIsDragEnabled.

    Using this as model I have a QListView initialized with:
    @ self.setAcceptDrops(True)
    self.setDefaultDropAction(Qt.MoveAction)
    self.setDragDropMode(QAbstractItemView.InternalMove)
    self.setDragDropOverwriteMode(False)
    self.setDragEnabled(True)
    self.setDropIndicatorShown(True)@

    When I attempt to drag an item, the itemData() method is called and I can pull the item around -- but the no-drag icon (/) is shown and nothing happens on release.

    If I change the model flags() to return also Qt.ItemIsDropEnabled for any item, then the green copy-drag icon (+) is shown but when the mouse is released, the setItemData() method is called to replace the data of the item under the mouse and removeRows() is called to remove the dragged item row. So the model ends up with one fewer items.

    I just want the list view to let the user re-order the list by dragging. What am I missing?

    1 Reply Last reply
    0
    • J Offline
      J Offline
      jazzycamel
      wrote on 12 Dec 2012, 11:34 last edited by
      #2

      The root index needs to accept drops but the items don't. The following is a working example, the flags() implementation should solve your problem I think:

      @
      from PyQt4.QtCore import *
      from PyQt4.QtGui import *

      class ListModel(QAbstractListModel):
      def init(self, parent=None):
      QAbstractListModel.init(self, parent)

          self._data=["Row %d" % i for i in xrange(10)]
      
      def rowCount(self, parent=QModelIndex()):
          if parent.isValid(): return 0
          return len(self._data)
      
      def data(self, index, role=Qt.DisplayRole):
          if not index.isValid(): return QVariant()
          if role==Qt.DisplayRole: return self._data[index.row()]
          return QVariant()
      
      def flags(self, index):
          if index.isValid(): 
              return Qt.ItemIsSelectable|Qt.ItemIsDragEnabled|Qt.ItemIsEnabled
      
          return Qt.ItemIsSelectable|Qt.ItemIsDragEnabled| \
                      Qt.ItemIsDropEnabled|Qt.ItemIsEnabled
      
      def insertRows(self, row, count, parent=QModelIndex()):
          if parent.isValid(): return False
      
          beginRow=max(0,row)
          endRow=min(row+count-1,len(self._data))
      
          self.beginInsertRows(parent, beginRow, endRow)
      
          for i in xrange(beginRow, endRow+1): self._data.insert(i,"")
      
          self.endInsertRows()
          return True
      
      def setData(self, index, value, role=Qt.EditRole):
          if not index.isValid() or role!=Qt.DisplayRole: return False
          
          self._data[index.row()]=str(value.toString())
          self.dataChanged.emit(index,index)
          return True
      
      def removeRows(self, row, count, parent=QModelIndex()):
          if parent.isValid(): return False
          if row>=len(self._data) or row+count<=0: return False
      
          beginRow=max(0,row)
          endRow=min(row+count-1,len(self._data)-1)
      
          self.beginRemoveRows(parent, beginRow, endRow)
      
          for i in xrange(beginRow, endRow+1): self._data.pop(i)
      
          self.endRemoveRows()
          return True
      

      class ListView(QListView):
      def init(self, model, parent=None):
      QTreeView.init(self, parent)

          self.setModel(model)
          self.setMovement(QListView.Snap)
          self.setDragDropMode(QListView.InternalMove)
          self.setDragDropOverwriteMode(False)
      

      class Window(QWidget):
      def init(self, parent=None):
      QWidget.init(self, parent)

          l=QHBoxLayout(self)
      
          self.model=ListModel(self)
          self.view=ListView(self.model)
          l.addWidget(self.view)
      

      if name=="main":
      from sys import argv, exit
      a=QApplication(argv)
      w=Window()
      w.show()
      w.raise_()
      exit(a.exec_())
      @

      Hope this helps ;o)

      For the avoidance of doubt:

      1. All my code samples (C++ or Python) are tested before posting
      2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
      1 Reply Last reply
      0
      • D Offline
        D Offline
        dcortesi
        wrote on 12 Dec 2012, 18:54 last edited by
        #3

        It helps very much in fact it solved the problem! All I had to do was recode the flags() and rowCount() methods to match yours, and it worked. I was ignoring the parent index.

        I find the role of the parent index very confusing. It is discussed in http://doc.qt.digia.com/qt/model-view-programming.html but not in these practical terms.

        1 Reply Last reply
        0
        • J Offline
          J Offline
          jazzycamel
          wrote on 12 Dec 2012, 19:23 last edited by
          #4

          All of Qt's models are essentially tree models. List models are a tree with only one level of branches and only one column (see diagrams "here":http://doc.qt.digia.com/qt/model-view-programming.html#basic-concepts). In basic terms, the view has to have a single entry point to the model structure and this is the root index. In the case of list and table models this is the parent of all cells in the model.

          Looking at "this":http://doc.qt.digia.com/qt/itemviews-simpletreemodel.html example of a tree structure you'll see where all this functionality is fully leveraged. It essentially works like a double linked list.

          Anywho, glad I could help, can you mark this thread as [SOLVED] if that's the case.

          For the avoidance of doubt:

          1. All my code samples (C++ or Python) are tested before posting
          2. As of 23/03/20, my Python code is formatted to PEP-8 standards using black from the PSF (https://github.com/psf/black)
          1 Reply Last reply
          0
          • D Offline
            D Offline
            dscyw
            wrote on 2 Jan 2014, 07:24 last edited by
            #5

            I am busying with finding out the way I can implementing the same thing as dcortesi did.So far nothing achieved.This thread gives me tips,but I still have lots to learn. Thx you two,dcortesi and jazzycamel.

            1 Reply Last reply
            0
            • D Offline
              D Offline
              dscyw
              wrote on 2 Jan 2014, 07:33 last edited by
              #6

              [quote author="dcortesi" date="1355338472"]It helps very much in fact it solved the problem! All I had to do was recode the flags() and rowCount() methods to match yours, and it worked. I was ignoring the parent index.

              I find the role of the parent index very confusing. It is discussed in http://doc.qt.digia.com/qt/model-view-programming.html but not in these practical terms.[/quote]

              This thread you posted give me much help.Can you give me some snippets that must can save me lots of time.I need to achieve it as soon as possible.Thanks.

              1 Reply Last reply
              0
              • GrumpyWizardG Offline
                GrumpyWizardG Offline
                GrumpyWizard
                wrote on 6 Dec 2017, 19:04 last edited by
                #7

                I know this is a really old post, but figured I'll update it because it was helpful to me. The solution provide here didn't work 100%. I had to also provide implementations for supportedDragActions() and supportedDropActions(), both of which returned MoveAction. Then it worked great.

                The differences for me are (1) I'm working in C++ and (2) I'm on version 5.6.2

                Thanks!

                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