Tuesday 11 March 2014

Excellent QT Drag and Drop Tutorial

This link is what got me started in understanding how QT works with drag and drop. I will post a link to the file in my github account that will use the results of this tutorial (although it is subject to change over time), but with code samples in-page.

http://rowinggolfer.blogspot.ca/2010/04/pyqt4-modelview-drag-drop-example.html

Here is my github source file with drag and drop classes in them:
https://github.com/NucleaPeon/QTCIDE/blob/master/src/view/main/widget.py

Note the following sections:

class Droppable(QtGui.QLabel):
    
    def __init__(self):
        super(Droppable, self).__init__()
        self.mime = QtCore.QMimeData()
        # ... more

    def mousePressEvent(self, event):
        mime = QtCore.QMimeData()
        mime.setText(self.mime.text())
        hotSpot = event.pos()
        mime.setData("application/x-hotspot", str(hotSpot.x()))
        
        # Create a pixmap of size of self
        pixmap = QtGui.QPixmap(self.size())
        self.render(pixmap)
        drag = QtGui.QDrag(self)
        drag.setMimeData(mime)
        drag.setPixmap(pixmap)
        drag.setHotSpot(hotSpot)
        
        dropAction = drag.exec_(QtCore.Qt.CopyAction|QtCore.Qt.MoveAction, QtCore.Qt.CopyAction)
Important things to note is that droppable object is a QtGui object, therefore has a visual place in the UI, has methods such as mousePressEvent in them.

Another odd thing you may notice, is that __init__ has a variable named self.mime, whereas mousePressEvent has just mime. Through trial and error, I found that the mousePressEvent method requires an instantiation *each* time the mouse is pressed, otherwise it fails to work. I set a variable in __init__ so that I only have one copy of the data and don't need to keep setting it (hardcoding == bad) in the method itself; changing the constructor variable will change the behaviour of the entire class easily.

class DropCanvas(QtGui.QGraphicsView):
    
    def __init__(self):
        super(DropCanvas, self).__init__()
        self.setAcceptDrops(True)
        self.scene = model.scene.ProjectScene()
        
    def dropEvent(self, event):
        # Here is where you put actions you want when the drop is done
        
        
    def dragEnterEvent(self, event):
        event.accept()

This class is the QtGui droppable object. I have it set to QGraphicsView, but it can be anything, such as a different view or a dock or panel, provided it inherits QWidget (I think).

Personally, I have an object that is set up specifically upon a drop event. The code here won't work with a QGraphicsView, but it used to be a QListView so it did work.

class CanvasItem(QtGui.QStandardItem):
    
    def __init__(self, *args, **kwargs):
        super(CanvasItem, self).__init__(*args)
        self.setEditable(False)


The item inherits a standard item and disables editing of itself.


Put all of the classes together and you can drag and drop!

No comments:

Post a Comment