# 在 PySide 中拖放

> 原文： [http://zetcode.com/gui/pysidetutorial/dragdrop/](http://zetcode.com/gui/pysidetutorial/dragdrop/)

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

在计算机图形用户界面中，拖放是单击虚拟对象并将其拖动到其他位置或另一个虚拟对象上的动作（或支持以下动作）。 通常，它可用于调用多种动作，或在两个抽象对象之间创建各种类型的关联。 （维基百科）

拖放功能是图形用户界面最明显的方面之一。 拖放操作使用户可以直观地完成复杂的事情。

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

## 简单的拖放

在第一个示例中，我们将具有`QtGui.QLineEdit`和`QtGui.QPushButton`。 我们将从行编辑小部件中拖动纯文本并将其拖放到按钮小部件上。

```py
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PySide tutorial 

This is a simple drag and
drop example.  

author: Jan Bodnar
website: zetcode.com 
last edited: August 2011
"""

import sys
from PySide import QtGui, QtCore

class Button(QtGui.QPushButton):

    def __init__(self, title, parent):
        super(Button, self).__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(QtGui.QWidget):

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

        self.initUI()

    def initUI(self):      

        qe = QtGui.QLineEdit('', self)
        qe.setDragEnabled(True)
        qe.move(30, 65)

        button = Button("Button", self)
        button.move(190, 65) 

        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Simple Drag & Drop')
        self.show()              

def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

```

简单拖动&放下操作。

```py
class Button(QtGui.QPushButton):

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

```

为了在`QtGui.QPushButton`小部件上放置文本，我们必须重新实现一些方法。 因此，我们创建了自己的`Button`类，该类将从`QtGui.QPushButton`类继承。

```py
self.setAcceptDrops(True)

```

我们为小部件启用放置事件。

```py
def dragEnterEvent(self, e):

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

```

首先，我们重新实现`dragEnterEvent()`方法。 我们会告知数据类型，我们将接受。 在我们的情况下，它是纯文本。

```py
def dropEvent(self, e):
    self.setText(e.mimeData().text()) 

```

通过重新实现`dropEvent()`方法，我们将定义在放置事件上将要执行的操作。 在这里，我们更改按钮小部件的文本。

```py
qe = QtGui.QLineEdit('', self)
qe.setDragEnabled(True)

```

`QtGui.QLineEdit`小部件具有对拖动操作的内置支持。 我们需要做的就是调用`setDragEnabled()`方法来激活它。

![Simple Drag & Drop](img/92c6a75ff01e1d30cea906fc95fa1f25.jpg)

图：简单 Drag & Drop

## 拖动和放置一个按钮小部件

在下面的示例中，我们将演示如何拖放按钮小部件。

```py
#!/usr/bin/python
# -*- coding: utf-8 -*-

"""
ZetCode PySide tutorial 

In this example, we drag and drop a
button.

author: Jan Bodnar
website: zetcode.com 
last edited: August 2011
"""

import sys
from PySide import QtGui, QtCore

class Button(QtGui.QPushButton):

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

    def mouseMoveEvent(self, e):

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

        mimeData = QtCore.QMimeData()

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

        dropAction = drag.start(QtCore.Qt.MoveAction)

    def mousePressEvent(self, e):

        QtGui.QPushButton.mousePressEvent(self, e)
        if e.button() == QtCore.Qt.LeftButton:
            print 'press'

class Example(QtGui.QWidget):

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

        self.initUI()

    def initUI(self):      

        self.setAcceptDrops(True)

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

        self.setGeometry(300, 300, 300, 150)
        self.setWindowTitle('Click or move')
        self.show()

    def dragEnterEvent(self, e):

        e.accept()

    def dropEvent(self, e):

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

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

def main():

    app = QtGui.QApplication(sys.argv)
    ex = Example()
    sys.exit(app.exec_())

if __name__ == '__main__':
    main()

```

在我们的代码示例中，窗口上有一个`QtGui.QPushButton`。 如果我们用鼠标左键单击该按钮，则会在控制台上打印`'press'`。 通过右键单击并移动按钮，我们在按钮小部件上执行拖放操作。

```py
class Button(QtGui.QPushButton):

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

```

我们创建一个`Button`类，该类将从`QtGui.QPushButton`派生。 我们还重新实现了`QtGui.QPushButton`的两种方法`mouseMoveEvent()`和`mousePressEvent()`。`mouseMoveEvent()`方法是拖放操作开始的地方。

```py
if event.buttons() != QtCore.Qt.RightButton:
    return

```

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

```py
mimeData = QtCore.QMimeData()

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

```

在这里，我们创建一个`QtGui.QDrag`对象。

```py
dropAction = drag.start(QtCore.Qt.MoveAction)

```

拖动对象的`start()`方法开始拖放操作。

```py
def mousePressEvent(self, e):

    QtGui.QPushButton.mousePressEvent(self, e)
    if e.button() == QtCore.Qt.LeftButton:
        print 'press'

```

如果我们用鼠标左键单击按钮，我们将在控制台上打印`'press'`。 注意，我们也在父对象上调用了`mousePressEvent()`方法。 否则，我们将看不到按钮被按下。

```py
position = e.pos()

self.btn.move(position)

```

在`dropEvent()`方法中，我们编码释放鼠标键并完成放置操作后发生的情况。 我们找出当前鼠标指针的位置并相应地移动一个按钮。

```py
e.setDropAction(QtCore.Qt.MoveAction)
e.accept()

```

我们指定放置动作的类型。 在我们的情况下，这是一个动作。

PySide 教程的这一部分专门用于拖放。