一、提要
在窗口编程中, 拖放是图形用户界面的一部分。拖放操作使用户能够直观地做复杂的事情。拖放功能显得特别酷,还有些神秘,本篇我们将讨论拖放操作,供初学者模仿。
在计算机图形用户界面中,拖放是单击虚拟对象并将其拖动到不同位置或另一个虚拟对象上的动作(或支持动作)。一般来说,它可以用来调用多种动作,或者在两个抽象对象之间创建各种类型的关联。
通常,我们可以拖放两件事:数据或一些图形对象。如果我们将图像从一个应用程序拖到另一个应用程序,我们拖放二进制数据。如果我们在 Firefox 中拖动一个选项卡并将其移动到另一个位置,我们就会拖放一个图形组件。
二、PyQt5简单拖放
2.1 QDrag
QDrag 支持基于 MIME 的拖放数据传输。它处理拖放操作的大部分细节。传输的数据包含在 QMimeData 对象中。
在第一个示例中,我们有一个 QLineEdit 和一个 QPushButton。我们将纯文本从行编辑小部件拖放到按钮小部件上。按钮的标签会改变。
2.2 简单信息拖放
simple_dragdrop.py
#!/usr/bin/python
"""
ZetCode PyQt5 tutorial
This is a simple drag and
drop example.
Author: Jan Bodnar
Website: zetcode.com
"""
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, 65)
button = Button("Button", self)
button.move(190, 65)
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 方法来激活它。

2.3 窗口之间拖放
以下示例演示如何拖放按钮小部件。
drag_button.py
#!/usr/bin/python
"""
ZetCode PyQt5 tutorial
In this program, we can press on a button with a left mouse
click or drag and drop the button with the right mouse click.
Author: Jan Bodnar
Website: zetcode.com
"""
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()
在我们的代码示例中,我们在窗口上有一个 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')
如果我们用鼠标左键单击按钮,我们会将“按下”打印到控制台。请注意,我们也在父级上调用了 mousePressEvent 方法。否则,我们将看不到按钮被按下。
position = e.pos()
self.button.move(position)
在 dropEvent 方法中,我们指定释放鼠标按钮并完成放置操作后会发生什么。在我们的例子中,我们找出当前鼠标指针的位置并相应地移动按钮。
e.setDropAction(Qt.MoveAction)
e.accept()
我们使用 setDropAction 指定放置动作的类型。在我们的例子中,它是一个移动动作。