Alex
Alex

Reputation: 7047

dropEvent not firing in PyQt5

I'm trying to implement Drag&Drop in my application, but the dropEvent in the target widget is never called.

I searched this problem a lot but every solution I found involves overriding dragMoveEvent, which I did, but with no difference.

This example code for me is not working either, for the above reason:

Main window class:

class Win(QtWidgets.QWidget):
    def __init__(self):
        super(Win, self).__init__()
        self.setGeometry(200, 300, 400, 200)
        self.setLayout(QtWidgets.QHBoxLayout())
        self.layout().addWidget(DragLabel())
        self.layout().addWidget(DropTest())

Label to drag:

class DragLabel(QtWidgets.QLabel):
    def __init__(self):
        super(DragLabel, self).__init__()
        self.setText("Drag me")

    def mouseMoveEvent(self, e):
        if e.buttons() != QtCore.Qt.LeftButton:
            return

        mimeData = QtCore.QMimeData()
        mimeData.setText("Test drop")

        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)

        dropAction = drag.exec(QtCore.Qt.CopyAction)

Widget to drop onto:

class DropTest(QtWidgets.QWidget):
    def __init__(self):
        super(DropTest, self).__init__()
        self.setAcceptDrops(True)

    def dragEnterEvent(self, e):
        print("DragEnter")
        e.accept()

    def dragMoveEvent(self, e):
        print("DragMove")
        e.accept()

    def dropEvent(self, e):
        print("DropEvent")
        position = e.pos()
        print(position)
        e.accept()

When I drag the label onto the other widget I see that both dragEnterEvent and dragMoveEvent are being called, but when I actually drop the label I get no message from the dropEvent function.

Plus, after closing the window the application will hang and won't quit.

I'm using PyQt 5.13.1 x86_64 installed with DNF in Fedora 31. Python version is 3.7.5 with no virtualenv.

Upvotes: 1

Views: 2456

Answers (2)

eyllanesc
eyllanesc

Reputation: 244311

As noted in a comment I had already answered the same question in this post, and I have tested it in a docker with fedora31 and it works correctly so after a discussion with the OP he pointed out it in a comment:

[PyQt5] was previously installed from DNF, but I'm pretty sure setuptools also installed it from pip as a dependency of my application.

The cause of the problem is that the OP is combining 2 ways of installation: dnf and pip, which each compiles with different versions of Qt, compilation flags, etc. that can cause certain functionalities to fail. The solution is to uninstall PyQt5 by both methods and reinstall only one of them.

Upvotes: 4

S. Nick
S. Nick

Reputation: 13701

Try it:

import sys
from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtCore import *
from PyQt5.QtGui import *
from PyQt5.QtWidgets import *


class DropTest(QtWidgets.QLabel):                       # - QWidget    + QLabel
    def __init__(self):
        super(DropTest, self).__init__()
        self.setAcceptDrops(True)
        self.setText(" Accept Drops")
        self.setStyleSheet("QLabel { background-color : #ccd; color : blue; font-size: 20px;}")

    def dragEnterEvent(self, e):
#        print("DragEnter")
        e.accept()

    def dragMoveEvent(self, e):
#        print("DragMove")
        e.accept()

    def dropEvent(self, e):
#        print("DropEvent")
#        position = e.pos()
#        print(position)

        self.setText(e.mimeData().text())                #  +++
        e.setDropAction(Qt.MoveAction)                   #  +++

        e.accept()


class DragLabel(QtWidgets.QLabel):
    def __init__(self):
        super(DragLabel, self).__init__()
        self.setText("Drag me")

    def mouseMoveEvent(self, e):
        if e.buttons() != QtCore.Qt.LeftButton:
            return
        mimeData = QtCore.QMimeData()
        mimeData.setText(self.text())                     #   ("Test drop")
        drag = QtGui.QDrag(self)
        drag.setMimeData(mimeData)
        dropAction = drag.exec(QtCore.Qt.CopyAction)


class Win(QtWidgets.QWidget):
    def __init__(self):
        super(Win, self).__init__()
        self.setGeometry(200, 300, 400, 200)

        self.setLayout(QtWidgets.QHBoxLayout())
        self.layout().addWidget(DragLabel())
        self.layout().addWidget(DropTest())


if __name__ == '__main__':
    app = QApplication(sys.argv)
    w = Win()
    w.show()
    sys.exit(app.exec_())        

enter image description here

Upvotes: 1

Related Questions