ZetCode

PyQt4 中的拖放操作

最后修改于 2023 年 10 月 18 日

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

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

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

通常,我们可以拖放两样东西:数据或一些图形对象。如果我们将图像从一个应用程序拖到另一个应用程序,我们拖放的是二进制数据。如果我们在 Firefox 中拖动一个标签并将其移动到另一个地方,我们拖放的是一个图形组件。

简单的拖放

在第一个示例中,我们有一个 QtGui.QLineEdit 和一个 QtGui.QPushButton。我们将纯文本从行编辑小部件拖放到按钮小部件上。按钮的标签将发生更改。

#!/usr/bin/python

"""
ZetCode PyQt4 tutorial

This is a simple drag and
drop example. 

author: Jan Bodnar
website: zetcode.com
last edited: January 2015
"""

import sys
from PyQt4 import QtGui

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):

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

        button = Button("Button", self)
        button.move(190, 65)
        
        self.setWindowTitle('Simple drag & drop')
        self.setGeometry(300, 300, 300, 150)


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

if __name__ == '__main__':
    main()   

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

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

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

self.setAcceptDrops(True)

我们为小部件启用了拖放事件。

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 方法,我们定义了在拖放事件发生时要执行的操作。在这里,我们更改了按钮小部件的文本。

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

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

Simple drag & drop
图:简单的拖放

拖放按钮小部件

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

#!/usr/bin/python

"""
ZetCode PyQt4 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
last edited: October 2013
"""

import sys
from PyQt4 import QtCore, QtGui


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):
      
        super(Button, self).mousePressEvent(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.button = Button('Button', self)
        self.button.move(100, 65)

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

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

    def dropEvent(self, e):

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

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

def main():
  
    app = QtGui.QApplication([])
    ex = Example()
    sys.exit(app.exec_())


if __name__ == '__main__':
    main()

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

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

我们创建了一个将派生自 QtGui.QPushButtonButton 类。我们还重新实现了 QtGui.QPushButton 的两个方法:mouseMoveEventmousePressEventmouseMoveEvent 方法是拖放操作开始的地方。

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

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

mimeData = QtCore.QMimeData()

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

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

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

拖放对象的 start 方法启动拖放操作。

def mousePressEvent(self, e):
  
    super(Button, self).mousePressEvent(e)
    
    if e.button() == QtCore.Qt.LeftButton:
        print 'press'

如果我们用鼠标左键单击按钮,则将“press”打印到控制台。请注意,我们还调用了父类的 mousePressEvent 方法。否则,我们将看不到按钮被按下。

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

dropEvent 方法中,我们编写了释放鼠标按钮并完成拖放操作后要执行的代码。我们找出当前鼠标指针的位置,并相应地移动按钮。

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

我们指定拖放操作的类型。在我们的例子中,它是一个移动操作。

PyQt4 教程的这一部分专门介绍了拖放操作。