При перетаскивании между вижетами не срабатывает dropEvent

Рейтинг: 0Ответов: 1Опубликовано: 17.01.2023

Я пытаюсь добиться поведения, при котором, при перетаскивании кнопки MyButton, dropEvent срабатывал бы в любой части интерфейса. Сейчас это работает почти так как нужно, за исключением одного обстоятельства. dropEvent не срабатывает если кнопка мыши отпускается между виджетами, и я не знаю как устранить эту проблему. Для меня очень важно что бы dropEvent срабатывал всегда, в момент окончания перетаскивания, так как в этот момент я посылаю на сервер сообщение о сделанном ходе, и если в этот момент мышь находилась между виджетами, то это сообщение не посылается.

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'DS_Test.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QDragEnterEvent, QDropEvent


class MyButton(QtWidgets.QPushButton):
    def mouseMoveEvent(self, event):
        btn_img = self.grab()
        painter = QtGui.QPainter(btn_img)
        painter.setCompositionMode(painter.CompositionMode_DestinationIn)
        painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150))
        painter.end()

        data = QtCore.QMimeData()
        drag = QtGui.QDrag(self)
        drag.setMimeData(data)
        drag.setPixmap(btn_img)

        drag.setHotSpot(event.pos())
        self._pos = event.pos()

        drag.exec_(QtCore.Qt.CopyAction)
        super(MyButton, self).mouseMoveEvent(event)


class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAcceptDrops(True)
    def dragEnterEvent(self, e: QDragEnterEvent):
        e.accept()

    def dragMoveEvent(self, e):
        e.accept()

    def dropEvent(self, e: QDropEvent):
        self.parent().dropEvent(e)


class MyQDialog(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)

    def dropEvent(self, e: QDropEvent):
        print("dropEvent - is done")
        e.accept()

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(1051, 800)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalFrame = MyFrame(Dialog)
        self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
        self.horizontalFrame.setObjectName("horizontalFrame")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.pushButton_3 = MyButton(self.horizontalFrame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_6.addWidget(self.pushButton_3)
        self.pushButton_2 = MyButton(self.horizontalFrame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_6.addWidget(self.pushButton_2)
        self.pushButton = MyButton(self.horizontalFrame)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.pushButton)
        self.verticalLayout.addWidget(self.horizontalFrame)
        self.horizontalFrame_2 = MyFrame(Dialog)
        self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
        self.horizontalFrame_2.setObjectName("horizontalFrame_2")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.verticalLayout.addWidget(self.horizontalFrame_2)
        self.horizontalFrame_3 = MyFrame(Dialog)
        self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
        self.horizontalFrame_3.setObjectName("horizontalFrame_3")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout.addWidget(self.horizontalFrame_3)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setText(_translate("Dialog", "PushButton"))
        self.pushButton_2.setText(_translate("Dialog", "PushButton"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = MyQDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())

Ответы

▲ 1

Я добавил dragEnterEvent и dragMoveEvent в MyQDialog. Теперь всё работает как как мне надо. Вот исправленный код

# -*- coding: utf-8 -*-

# Form implementation generated from reading ui file 'DS_Test.ui'
#
# Created by: PyQt5 UI code generator 5.15.7
#
# WARNING: Any manual changes made to this file will be lost when pyuic5 is
# run again.  Do not edit this file unless you know what you are doing.


from PyQt5 import QtCore, QtGui, QtWidgets
from PyQt5.QtGui import QDragEnterEvent, QDropEvent


class MyButton(QtWidgets.QPushButton):
    def mouseMoveEvent(self, event):
        btn_img = self.grab()
        painter = QtGui.QPainter(btn_img)
        painter.setCompositionMode(painter.CompositionMode_DestinationIn)
        painter.fillRect(btn_img.rect(), QtGui.QColor(0, 0, 0, 150))
        painter.end()

        data = QtCore.QMimeData()
        drag = QtGui.QDrag(self)
        drag.setMimeData(data)
        drag.setPixmap(btn_img)

        drag.setHotSpot(event.pos())
        self._pos = event.pos()

        drag.exec_(QtCore.Qt.CopyAction)
        super(MyButton, self).mouseMoveEvent(event)


class MyFrame(QtWidgets.QFrame):
    def __init__(self, parent):
        super().__init__(parent)
        self.setAcceptDrops(True)

    def dragEnterEvent(self, e: QDragEnterEvent):
        e.accept()

    def dragMoveEvent(self, e):
        e.accept()

    def dropEvent(self, e: QDropEvent):
        self.parent().dropEvent(e)


class MyQDialog(QtWidgets.QDialog):
    def __init__(self):
        super().__init__()
        self.setAcceptDrops(True)

    def dragEnterEvent(self, e: QDragEnterEvent):
        e.accept()

    def dragMoveEvent(self, e):
        e.accept()

    def dropEvent(self, e: QDropEvent):
        print("dropEvent - is done")
        e.accept()

class Ui_Dialog(object):
    def setupUi(self, Dialog):
        Dialog.setObjectName("Dialog")
        Dialog.resize(1051, 800)
        self.verticalLayout = QtWidgets.QVBoxLayout(Dialog)
        self.verticalLayout.setObjectName("verticalLayout")
        self.horizontalFrame = MyFrame(Dialog)
        self.horizontalFrame.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(255, 0, 0, 211), stop:0.166 rgba(255, 255, 0, 211), stop:0.333 rgba(0, 255, 0, 211), stop:0.5 rgba(0, 255, 255, 211), stop:0.666 rgba(0, 0, 255, 211), stop:0.833 rgba(255, 0, 255, 211), stop:1 rgba(255, 0, 0, 211));")
        self.horizontalFrame.setObjectName("horizontalFrame")
        self.horizontalLayout_6 = QtWidgets.QHBoxLayout(self.horizontalFrame)
        self.horizontalLayout_6.setObjectName("horizontalLayout_6")
        self.pushButton_3 = MyButton(self.horizontalFrame)
        self.pushButton_3.setObjectName("pushButton_3")
        self.horizontalLayout_6.addWidget(self.pushButton_3)
        self.pushButton_2 = MyButton(self.horizontalFrame)
        self.pushButton_2.setObjectName("pushButton_2")
        self.horizontalLayout_6.addWidget(self.pushButton_2)
        self.pushButton = MyButton(self.horizontalFrame)
        self.pushButton.setObjectName("pushButton")
        self.horizontalLayout_6.addWidget(self.pushButton)
        self.verticalLayout.addWidget(self.horizontalFrame)
        self.horizontalFrame_2 = MyFrame(Dialog)
        self.horizontalFrame_2.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:0, x2:1, y2:0, stop:0 rgba(9, 41, 4, 255), stop:0.085 rgba(2, 79, 0, 255), stop:0.19 rgba(50, 147, 22, 255), stop:0.275 rgba(236, 191, 49, 255), stop:0.39 rgba(243, 61, 34, 255), stop:0.555 rgba(135, 81, 60, 255), stop:0.667 rgba(121, 75, 255, 255), stop:0.825 rgba(164, 255, 244, 255), stop:0.885 rgba(104, 222, 71, 255), stop:1 rgba(93, 128, 0, 255));")
        self.horizontalFrame_2.setObjectName("horizontalFrame_2")
        self.horizontalLayout_7 = QtWidgets.QHBoxLayout(self.horizontalFrame_2)
        self.horizontalLayout_7.setObjectName("horizontalLayout_7")
        self.verticalLayout.addWidget(self.horizontalFrame_2)
        self.horizontalFrame_3 = MyFrame(Dialog)
        self.horizontalFrame_3.setStyleSheet("background-color: qlineargradient(spread:pad, x1:0, y1:1, x2:0, y2:0, stop:0 rgba(0, 0, 0, 255), stop:0.05 rgba(14, 8, 73, 255), stop:0.36 rgba(28, 17, 145, 255), stop:0.6 rgba(126, 14, 81, 255), stop:0.75 rgba(234, 11, 11, 255), stop:0.79 rgba(244, 70, 5, 255), stop:0.86 rgba(255, 136, 0, 255), stop:0.935 rgba(239, 236, 55, 255));")
        self.horizontalFrame_3.setObjectName("horizontalFrame_3")
        self.horizontalLayout_8 = QtWidgets.QHBoxLayout(self.horizontalFrame_3)
        self.horizontalLayout_8.setObjectName("horizontalLayout_8")
        self.verticalLayout.addWidget(self.horizontalFrame_3)

        self.retranslateUi(Dialog)
        QtCore.QMetaObject.connectSlotsByName(Dialog)

    def retranslateUi(self, Dialog):
        _translate = QtCore.QCoreApplication.translate
        Dialog.setWindowTitle(_translate("Dialog", "Dialog"))
        self.pushButton_3.setText(_translate("Dialog", "PushButton"))
        self.pushButton_2.setText(_translate("Dialog", "PushButton"))
        self.pushButton.setText(_translate("Dialog", "PushButton"))


if __name__ == "__main__":
    import sys
    app = QtWidgets.QApplication(sys.argv)
    Dialog = MyQDialog()
    ui = Ui_Dialog()
    ui.setupUi(Dialog)
    Dialog.show()
    sys.exit(app.exec_())