翻译自原文:Drag and drop in PyQt5

翻译时间 2020 年 8 月 20 日

在 PyQt5 教程的这一部分中,我们将讨论拖放操作。

在计算机图形用户界面中,拖放是单击虚拟对象并将其拖动到其他位置或其他虚拟对象的操作(或支持的操作)。通常,它可用于调用多种类型的操作,或在两个抽象对象之间创建各种类型的关联。

拖放是图形用户界面的一部分。拖放操作使用户能够直观地执行复杂操作。

通常,我们可以拖放两件事情:数据或一些图形对象。如果我们将图像从一个应用程序拖到另一个应用程序,我们会拖放二进制数据。如果我们在 Firefox 中拖动一个选项卡并将其移动到另一个位置,我们会拖放图形组件。

QDrag

QDrag为基于 MIME 的拖放数据传输提供支持。它处理拖放操作的绝大多数详细信息。传输的数据存放在QMimeData对象中。

PyQt5 中的简单拖放示例

在第一个示例中,我们使用QLineEditQPushButton。我们从行编辑部件拖动纯文本,并将其拖放到按钮小部件上,按钮的标签将更改。

simple_dragdrop.py

import sys

from PyQt5.QtWidgets import (QPushButton, QWidget,
                             QLineEdit, QApplication)


class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

        self.setAcceptDrops(True)

    def dragEnterEvent(self, e):

        if e.mimeData().hasFormat('text/plain'):
            e.accept()
        else:
            e.ignore()

    def dropEvent(self, e):

        self.setText(e.mimeData().text())


class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        edit = QLineEdit('', self)
        edit.setDragEnabled(True)
        edit.move(30, 30)

        button = Button("Button", self)
        button.move(30, 60)

        self.setWindowTitle('Simple drag and drop')
        self.setGeometry(300, 300, 300, 150)


def main():

    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()


if __name__ == '__main__':
    main()

该示例提供了一个简单的拖放操作。

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

        ...

为了在QPushButton部件上放置文本,我们必须重新实现一些方法。因此,我们创建自己的类Button,继承自QPushButton

self.setAcceptDrops(True)

我们使用setAcceptDrops()启用部件的放置事件。

def dragEnterEvent(self, e):

    if e.mimeData().hasFormat('text/plain'):
        e.accept()
    else:
        e.ignore()

首先,我们重新实现dragEnterEvent()方法。我们会告知我们接受的被拖进来的数据类型。在我们的案例中,它是纯文本。

def dropEvent(self, e):

    self.setText(e.mimeData().text())

通过重新实现dropEvent()方法,我们定义了在drop事件中的操作。在这里,我们改变按钮部件的文本。

edit = QLineEdit('', self)
edit.setDragEnabled(True)

QLineEdit部件具有对拖动操作的内置支持。我们只需调用setDragEnabled()该方法来激活它。

image-20200820171620457

图:简单的拖放

拖放按钮小部件

下面的示例演示如何拖放按钮部件。

drag_button.py

import sys

from PyQt5.QtCore import Qt, QMimeData
from PyQt5.QtGui import QDrag
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication


class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

    def mouseMoveEvent(self, e):

        if e.buttons() != Qt.RightButton:
            return

        mimeData = QMimeData()

        drag = QDrag(self)
        drag.setMimeData(mimeData)
        drag.setHotSpot(e.pos() - self.rect().topLeft())

        dropAction = drag.exec_(Qt.MoveAction)

    def mousePressEvent(self, e):

        super().mousePressEvent(e)

        if e.button() == Qt.LeftButton:
            print('press')


class Example(QWidget):

    def __init__(self):
        super().__init__()

        self.initUI()

    def initUI(self):

        self.setAcceptDrops(True)

        self.button = Button('Button', self)
        self.button.move(100, 65)

        self.setWindowTitle('Click or Move')
        self.setGeometry(300, 300, 550, 450)

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

    def dropEvent(self, e):
        position = e.pos()
        self.button.move(position)

        e.setDropAction(Qt.MoveAction)
        e.accept()


def main():
    
    app = QApplication(sys.argv)
    ex = Example()
    ex.show()
    app.exec_()


if __name__ == '__main__':
    main()

在我们的代码示例中,我们有一个窗口。如果我们单击鼠标左键的按钮,则"press"消息将打印到控制台。通过右键单击并移动按钮,我们对按钮QPushButton部件执行拖放操作。

class Button(QPushButton):

    def __init__(self, title, parent):
        super().__init__(title, parent)

我们创建一个派生自QPushButton的类Button。我们还重新实现QPushButton的两种方法:mouseMoveEvent()mousePressEvent()mouseMoveEvent()方法是拖放操作开始的位置。

if e.buttons() != Qt.RightButton:
    return

在这里,我们决定,我们只能用鼠标右键执行拖放。左鼠标按钮保留用于单击该按钮。

mimeData = QMimeData()

drag = QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())

QDrag对象已创建。该类对基于 MIME 的拖放数据传输提供支持。

dropAction = drag.exec_(Qt.MoveAction)

拖动对象的exec_()方法启动拖放操作。

def mousePressEvent(self, e):

    super().mousePressEvent(e)

    if e.button() == Qt.LeftButton:
        print('press')

如果我们左键单击鼠标按钮,我们会将"press"到控制台。请注意,我们也在父级上调用mousePressEvent()方法。否则,我们不会看到按下按钮。

position = e.pos()
self.button.move(position)

dropEvent()方法中,我们指定释放鼠标按钮并完成放置操作后发生的情况。在我们的案例中,我们找出当前鼠标指针的位置,并相应地移动按钮。

e.setDropAction(Qt.MoveAction)
e.accept()

我们使用setDropAction()指定drop动作的类型。在我们的案例中,这是一个移动动作。

PyQt5 教程的这一部分专门用于拖放操作。