2
votes

I am trying to perform a drag and drop operation from a QTreeWidget to QGraphicsView. dragStart() works, and dragEnterEvent() works, but dropEvent() is never being called. Also the pixmap is not showing up until the cursor enters the QGraphicsView, which isn't a problem, but I just thought it would appear as soon as the drag started. Here is my startDrag function:

def on_list_startDrag(self, supportedActions):
    #Retreive the item that was clicked on
    currentPart = self.ui.list.currentItem()
    part = currentPart.text(0)

    drag = QtGui.QDrag(self.ui.list)
    mime = QtCore.QMimeData()
    print(part)
    #retreive that associated graphics file
    icon = QtGui.QIcon('drawings/FULL/' + part + '.svg')
    pixmap = icon.pixmap(102,122)

    selected = QtGui.QImage('drawings/FULL/' + part + '.svg')
    data = pickle.dumps(selected)

    mime.setData('application/x-item', data)
    #mime.setImageData(QtGui.QImage('drawings/FULL/' + part + '.svg'))
    drag.setMimeData(mime)
    drag.setHotSpot(QtCore.QPoint(pixmap.width()/2, pixmap.height()/2))
    drag.setPixmap(pixmap)
    drag.exec_()

Here is the the dragEnterEvent:

def on_workArea_dragEnterEvent(self, event):
    print(event.format())
    if (event.mimeData().hasFormat('application/x-item')):
        event.accept()
        print('accepted')
    else:
        event.ignore()

Finally the dropEvent code:

def on_workArea_dropEvent(self, event):
    print('dropped')

When I start the drag and drop operation is happening the cursor has the circle with the slash like the widget doesn't accept drops, but I set the QGraphicsView, workArea, to accept drops. Can someone please help me get the drop working and explain why the pixmap doesn't show up behind the cursor until the cursor is over the QGraphicsView. Thank you.

2

2 Answers

6
votes

You need to implement dragMoveEvent() as well, or dropEvent() won't be called. This is also what causes it to show a proper drop icon, instead of the slashed-circle "can't drop here" icon.

0
votes

I've checked your code and it does look and work fine for me; both dropEvent and pixmap work as expected. Perhaps there's smth else in your code which causes this unwanted behaviour you're describing. As for the dropEvent, you might have problems connecting slot to a signal, which leads to your code not being called. I've made a small example which does drag and drop between treeview and grahicsview and loads and presents a pixmap:

import sys
from PyQt4 import QtGui, QtCore

class TestTreeView(QtGui.QTreeView):
    def __init__(self, parent = None):
        super(TestTreeView, self).__init__(parent)
        self.setDragEnabled(True)

    def startDrag(self, dropAction):
        print('tree start drag')

        icon = QtGui.QIcon('/home/image.png')
        pixmap = icon.pixmap(64, 64)

        mime = QtCore.QMimeData()
        mime.setData('application/x-item', '???')

        drag = QtGui.QDrag(self)
        drag.setMimeData(mime)        
        drag.setHotSpot(QtCore.QPoint(pixmap.width()/2, pixmap.height()/2))
        drag.setPixmap(pixmap)        
        drag.start(QtCore.Qt.CopyAction)

class TestGraphicsView(QtGui.QGraphicsView): 
    def __init__(self, parent = None):
        super(TestGraphicsView, self).__init__(parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, event):
        print('graphics view drag enter')
        if (event.mimeData().hasFormat('application/x-item')):
            event.acceptProposedAction()
            print('accepted')
        else:
            event.ignore()    

    def dropEvent(self, event): 
        print('graphics view drop')
        event.acceptProposedAction()                 

class MainForm(QtGui.QMainWindow):
    def __init__(self, parent=None):
        super(MainForm, self).__init__(parent)

        self.model = QtGui.QStandardItemModel()

        for k in range(0, 4):
            parentItem = self.model.invisibleRootItem()
            for i in range(0, 4):
                item = QtGui.QStandardItem(QtCore.QString("item %0 %1").arg(k).arg(i))
                parentItem.appendRow(item)
                parentItem = item

        self.setMinimumSize(300, 400)

        self.view = TestTreeView(self)
        self.view.setModel(self.model)
        self.view.setMinimumSize(300, 200)

        self.graphicsView = TestGraphicsView(self)
        self.graphicsView.setGeometry(0, 210, 300, 400)        

        self.layout = QtGui.QVBoxLayout(self.centralWidget())        
        self.layout.addWidget(self.view)
        self.layout.addWidget(self.graphicsView)

def main():
    app = QtGui.QApplication(sys.argv)
    form = MainForm()
    form.show()
    app.exec_()

if __name__ == '__main__':
    main() 

hope this helps, regards