Home  Contents

Drag and Drop in PyQt4

Dieser Abschnitt des PyQt4-Tutorials beschäftigt sich mt Drag&Drop-Operationen.

Innerhalb grafischer Benutzeroberflächen handelt es sich bei Drag-and-Drop um das Anklicken und Ziehen eines virtuellen Objekts an eine andere Stelle oder auf ein anderes virtuelles Objekt. Es kann verwendet werden, um diverse Arten von Aktionen auszulösen oder verschiedene Arten von Verbindungen von zwei abstrakten Objekten zu erzeugen. (Quelle: Wikipedia)

Drag-and-Drop ist eine der offenkundigsten Funktionen grafischer Benutzeroberflächen und erlauben den Nutzern die intuitive Ausführung komplexer Handlungen.

Gewöhnlich lassen sich zwei Dinge per Drag-and-Dorp bewegen: Dateien oder bestimmte grafische Objekte. Wenn wir ein bild von einer Anwendung in die andere verschieben, bewegen wir Binärdaten. Wenn wir einen Tab in Firefox ziehen und andernorts ablegen, bewegen wir grafische Komponenten per Drag-and-Drop.

Einfaches Drag and Drop

Im ersten Beispiel verwenden wir QLineEdit und QPushButton. Wir werden Fließtext aus dem Zeilenbearbeitungs-Widget ziehen und auf das Knopf-Widget fallen lassen.

#!/usr/bin/python

# dragdrop.py

import sys
from PyQt4 import QtGui

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

    def dragEnterEvent(self, event):
        if event.mimeData().hasFormat('text/plain'):
            event.accept()
        else:
            event.ignore() 

    def dropEvent(self, event):
        self.setText(event.mimeData().text()) 


class DragDrop(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        self.resize(280, 150)
        self.setWindowTitle('Simple Drag & Drop')

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

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

        screen = QtGui.QDesktopWidget().screenGeometry()
        size =  self.geometry()
        self.move((screen.width()-size.width())/2, 
            (screen.height()-size.height())/2)

app = QtGui.QApplication(sys.argv)
icon = DragDrop()
icon.show()
app.exec_()

Einfache Drag-and-Drop-Operationen.

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

Um Text auf das QPushButton-Widget fallen lassen zu können, müssen wir einige Methoden reimplementieren. Also erzeugen wir unsere eigene Knopf-Klasse, die wir von der QPushButton-Klasse ableiten.

 self.setAcceptDrops(True)

Wir aktivieren die Drop-Ereignisse des Widgets.

 def dragEnterEvent(self, event):
     if event.mimeData().hasFormat('text/plain'):
         event.accept()
     else:
         event.ignore()

Zuerst überschreiben wir die dragEnterEvent()-Methode. Darin informieren wir über den von uns akzeptierten Datentyp - in unserem Fall Fließtext.

def dropEvent(self, event):
     self.setText(event.mimeData().text())

Durch Überschreiben der dropEvent()-Methode definieren wir, was bei einem Drop-Ereignis passiert. In diesem Fall ändern wir den Text des Knopf-Widgets.

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

Das QLineEdit-Widget verfügt über integrierte Unterstützung für Drag-Operationen. Daher müssen wir lediglich die setDragEnabled()-Methode aufrufen, um diesen zu aktivieren.

Einfaches Drag & Drop

Abbildung: Einfaches Drag & Drop

Drag & drop mit einem Knopf-Widget

In den folgenden Beispielen demonstrieren wir, wie man Drag-and-Drop auf ein Knopf-Widget anwenden kann.

#!/usr/bin/python

# dragbutton.py

import sys
from PyQt4 import QtGui
from PyQt4 import QtCore

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

    def mouseMoveEvent(self, event):

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

        mimeData = QtCore.QMimeData()

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

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

        if dropAction == QtCore.Qt.MoveAction:
            self.close()


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



class DragButton(QtGui.QDialog):
    def __init__(self, parent=None):
        QtGui.QDialog.__init__(self, parent)

        self.resize(280, 150)
        self.setWindowTitle('Click or Move')
        self.setAcceptDrops(True)

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


        screen = QtGui.QDesktopWidget().screenGeometry()
        size = self.geometry()
        self.move((screen.width()-size.width())/2, 
            (screen.height()-size.height())/2)


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

    def dropEvent(self, event):

        position = event.pos()
        button = Button('Button', self)
        
        button.move(position)
        button.show()

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


app = QtGui.QApplication(sys.argv)
db = DragButton()
db.show()
app.exec_()

In unserem Code-Beispiel haben wir einen QPushButton im Fenster. Wenn wir auf den Knopf mit der linken Maustaste klicken, erscheint in der Konsole 'press'. Durch Rechtsklicken und bewegen des Knopfs, erzeugen wir eine Drag-and-Drop-Operation mit dem Knopf-Widget durch.

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

Wir erzeugen eine Knopf-Klasse, die wir vom QPushButton ableiten. Außerdem überschreiben wir zwei Methoden dieses Widgets: mouseMoveEvent() und mousePressEvent(). Das mouseMoveEvent() ist der Ort, an dem die Drag-and-Drop-Operation beginnt.

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

Hier entscheidne wir, dass wir Drag-and-Drop nur mit der rechten Maustaste ausgeführt werden kann. Die linke Maustaste ist dafür reserviert, den Knopf zu drücken.

 mimeData = QtCore.QMimeData()

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

Hier erzeugen wir ein QDrag-Objekt.

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

 if dropAction == QtCore.Qt.MoveAction:
     self.close()

Die start()-Methode des Drag-Objekts startet die Drag-and-Drop-Operation. Wenn wir eine Move-Drop-Aktion durchführen, zerstören wir das Knopf-Widget. Technisch ausgedrückt zerstören wir ein Widget an der gegenwärtigen Position und wiedererzeugen es an einer neuen.

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

Wir geben 'press' in der Konsole aus, wenn wir mit auf den Knopf linksklicken. Beachten Sie, dass wir dabei auch die mousePressEvent()-Methode des Elternelements aufrufen. Andernfalls würden wir nicht sehen können, dass der Knopf gedrückt wurde.

 position = event.pos()
 button = Button('Close', self)
 button.move(position)
 button.show()

In der dropEvent()-Methode programmieren wir, was passiert, nachdem wir die Maustaste loslassen und die Drop-Operation beenden. In unserem Beispiel erzeugen wir ein neues Knopf-Widget an der gegenwärtigen Position des Mauszeigers.

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

Wir legen die Art der Drop-Aktion fest, in unserem Fall eine Move-Aktion.