过早地结束 QDrag

Ending a QDrag Prematurely

我希望我的应用程序在 dragLeaveEvent 中终止所有拖放操作,而无需用户松开鼠标按钮。

问题是循环会暂停所有可能在 QDrag 发生时取消的事件,即使文档指出:

"On Linux and Mac OS X, the drag and drop operation can take some time, but this function does not block the event loop. Other events are still delivered to the application while the operation is performed. On Windows, the Qt event loop is blocked during the operation. However, QDrag.exec() on Windows causes processEvents() to be called frequently to keep the GUI responsive. If any loops or operations are called while a drag operation is active, it will block the drag operation."

因此,我无法调用结束拖动的事件。

到目前为止,我已经尝试了建议 here,如代码所示。我使用的是 PyQt5,但如果解决方案在 Qt 中有效,那么它也应该在 PyQt 中有效。

编辑:我有点害怕删除拖动,因为场景不拥有它。我想我可以将它设置为拥有它,但是 posted here 它不应该工作。

Edit2:添加了我修复它的非工作尝试的代码。我真的很想解决这个问题,而不必制作自己的拖放框架。还修剪了 post.

import sys
from PyQt5.QtWidgets import (QMainWindow, QApplication,
    QGraphicsView, QGraphicsScene, QGraphicsWidget, QGraphicsRectItem)
from PyQt5.QtCore import (QMimeData, Qt, QByteArray, QCoreApplication,
    QEvent, QPoint)
from PyQt5.QtGui import QBrush, QColor, QDrag, QPen, QMouseEvent


class MainWindow(QMainWindow):
    def __init__(self):
        super().__init__()
        self.scene = CustomScene()
        self.view = QGraphicsView(self.scene, self)
        self.setGeometry(100, 100, 600, 600)
        self.view.setGeometry(0, 0, 500, 500)
        self.show()


class CustomScene(QGraphicsScene):
    def __init__(self):
        super().__init__()
        self.customWidgets = []
        for i in range(5):
            newItem = CustomDragWidget()
            self.addItem(newItem)
            self.customWidgets.append(newItem)
            newItem.setGeometry(i * 50, i * 50, 50, 50)

    def dragLeaveEvent(self, event):
        # Work your magic here. I've tried the following:
        # 1)
        self.customWidgets[0].dropEvent(event)
        # 2)
        self.dropEvent(event)
        # 3)
        eve = QMouseEvent(QEvent.MouseButtonRelease, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
        QCoreApplication.sendEvent(self.views()[0], eve)
        QCoreApplication.processEvents()
        # 4)
        eve = QMouseEvent(QEvent.MouseButtonRelease, QPoint(0, 0), Qt.LeftButton, Qt.LeftButton, Qt.NoModifier)
        QCoreApplication.sendEvent(self.customWidgets[0], eve)
        QCoreApplication.processEvents()

    def dropEvent(self, QGraphicsSceneDragDropEvent):
        # a dummy dropevent that tries to stop the drop, but doesnt work
        QGraphicsSceneDragDropEvent.accept()

class CustomDragWidget(QGraphicsWidget):
    def __init__(self,):
        super().__init__()
        self.squareItem = QGraphicsRectItem()
        self.squareItem.setBrush(QBrush(QColor(Qt.blue)))
        self.squareItem.setPen(QPen(QColor(Qt.black), 2))
        self.squareItem.setRect(0, 0, 50, 50)
        self.squareItem.setParentItem(self)
        self.setAcceptDrops(True)

    def mousePressEvent(self, event):
        mime = QMimeData()
        itemData = QByteArray()
        mime.setData('application/x-dnditemdata', itemData)
        drag = QDrag(self)
        drag.setMimeData(mime)
        drag.exec(Qt.MoveAction)

    def dropEvent(self, event):
        event.accept()


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

这有点老套,但似乎有效(在 Linux 上):

    def dragLeaveEvent(self, event):
        QCoreApplication.postEvent(self,
            QKeyEvent(QEvent.KeyPress, Qt.Key_Escape, Qt.NoModifier))