[PyQt] How to change the Drag & Drop cursor during a drag operation?

Ron Longo ron.longo at cox.net
Mon Nov 17 22:33:52 GMT 2008

I'm porting a Tkinter application to PyQt.  This is my first time using PyQt so I realize I may be doing this all wrong.  My application includes a QTreeView backed by my own model.  The view provides the user a means to hierarchically create, edit and organize large amounts of information.  Ordering of the nodes in the tree is important.  Consequently I've implemented several ways for the user to reorganize the tree including drag and drop reordering.

I've tried using QTreeView's built-in drag and drop.  It works OK, but I really need more than it can provide.  The built-in drag and drop always drops content <i>before</i> the entry under the mouse cursor.  However, I want to be able to drop content <i>before</i>, <i>after</i> or <i>as a child of</i> the entry under the mouse cursor.  The location (before, after or as a child of) is determined by the location of the drag cursor's hot spot relative to the rectangle over which it is currently hovering.  E.g. if the hot spot is hovering over the <i>top half</i> of an entry, the drop would occur <i>before</i> that entry, while if it's in the <i>bottom half</i> the drop would occur <i>after</i> the entry.  However, if it's in the <i>bottom half</I> <B>and</b> more than 20 pixels to the right of the left edge of the entry, it will be dropped as a child.  To provide feedback to the user as to where the drop will occur I wish to change the mouse cursor as the drag operation is taking place.

To implement all of this I've subclassed QTreeView and overridden mousePressEvent(), mouseMoveEvent(), dragMoveEvent(), dragEnterEvent(), dragLeaveEvent() and dropEvent() (as per the drag and drop documentation in TrollTech's Qt distribution).  In my constructor I have the following code:

      self.insertBefore_cursor  = RES.getDragCursor('OutlineView','DnD_insertBeforeCursor')
      self.insertAfter_cursor   = RES.getDragCursor('OutlineView','DnD_insertAfterCursor')
      self.insertChild_cursor   = RES.getDragCursor('OutlineView','DnD_insertChildCursor')

RES is a subclass object of python's SafeConfigParser which reads ini files.  My getDragCursor() reads in the following lines

DnD_insertBeforeCursor  = resources/cursors/arrow_insertBefore.png:14:12
DnD_insertAfterCursor   = resources/cursors/arrow_insertAfter.png:14:12
DnD_insertChildCursor   = resources/cursors/arrow_insertChild.png:22:12

getDragCursor() returns a tuple of two:  a QPixmap and a QPoint (the hot spot).  Next my dragMoveEvent()

   def dragMoveEvent( self, event ):
      referenceIndex,relation = self._dnd_insertionPos( event )

      if relation == 'before':
         pixmap, hotspot = self.insertBefore_cursor
      elif relation == 'after':
         pixmap, hotspot = self.insertAfter_cursor
      elif relation == 'child':
         pixmap, hotspot = self.insertChild_cursor
         raise Exception()
      self.drag.setDragCursor( pixmap, QtCore.Qt.CopyAction + QtCore.Qt.MoveAction )
      self.drag.setHotSpot( hotspot )

_dnd_insertionPos() calls event.pos(), does a bit of math and returns a tuple consisting of the referenceIndex (a QModelIndex for the item over which the mouse cursur is hovering) and a relation string ('before', 'after' or 'child').  I use this second value to select a cursor.

When I run my software and attempt a drag, all I see is the built-in drag cursor.  My own cursors are never displayed.  However, if I put a break point after the setDragCursor(), my cursor DOES get displayed.  This leads me to suspect that I may need to make some sort of call after setDropCursor() to give the event loop or drawing routines some processor time.

Thanks for the help.

Sorry about all the text here.  I wanted to be sure to provide enough info to allow a diagnosis.  Also, sorry that I haven't provided any runnable code to get a clearer indication of the problem.  There's quite a bit of code and I wasn't able to trim it down to a decent sized-example.  My complete project is up in googlecode in a project called MindTree if more context is needed to help diagnose this (or if you're just curious).
-------------- next part --------------
An HTML attachment was scrubbed...
URL: http://www.riverbankcomputing.com/pipermail/pyqt/attachments/20081117/16fbaf00/attachment.html

More information about the PyQt mailing list