Dieses Tutorial ist ernsthaft veraltet. QDrag.start
ist seit Qt 4.3 veraltet. QDrag.exec_
sollte stattdessen verwendet werden.
Wie Sie in der Dokumentation für exec
sehen können, hat es einen Rückgabewert. setDropAction
in dropEvent
bestimmt diesen Wert. Es führt den Umzug nicht durch. Deshalb brauchen Sie eine self.button.move()
, um die tatsächliche Bewegung zu tun. Also, was ist der Sinn einer setDropAction
? Sie müssen möglicherweise wissen, welche Art von Ziehen Sie ausgeführt haben. Stellen Sie sich vor, Sie implementieren Drag-Drop zwischen zwei Listen-Widgets. Wenn Sie eine Verschiebungsoperation ausgeführt haben, müssen Sie das Objekt aus dem Quellwidget entfernen und im Ziel erstellen. Wenn es sich um einen Kopiervorgang handelt, können Sie das Original belassen und lediglich eine Kopie im Ziel erstellen.
setHotSpot
/hotSpot
ist verwandt mit der einer QDrag
. Sie können eine QPixmap
anzeigen, während Sie das Element ziehen. hotSpot
bestimmt die Positionierung der Pixmap. Die Pixmap wird so positioniert, dass der Cursor bei hotSpot
relativ zur oberen linken Ecke der Pixmap steht. Im Fall dieses Tutorials ist es also ziemlich sinnlos, da kein Pixmap angezeigt werden muss.
Hier ist ein bisschen modifizierte und aktualisierte Version dieses Tutorials. Hoffentlich habe ich genug Kommentare aufgenommen. Sie können mit Right-Click
oder Kopie mit Shift + Right-Click
bewegen:
#!/usr/bin/python
# -*- coding: utf-8 -*-
import sys
from PyQt4 import QtGui, QtCore
class Button(QtGui.QPushButton):
def mouseMoveEvent(self, e):
if e.buttons() != QtCore.Qt.RightButton:
return
# write the relative cursor position to mime data
mimeData = QtCore.QMimeData()
# simple string with 'x,y'
mimeData.setText('%d,%d' % (e.x(), e.y()))
# let's make it fancy. we'll show a "ghost" of the button as we drag
# grab the button to a pixmap
pixmap = QtGui.QPixmap.grabWidget(self)
# below makes the pixmap half transparent
painter = QtGui.QPainter(pixmap)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(pixmap.rect(), QtGui.QColor(0, 0, 0, 127))
painter.end()
# make a QDrag
drag = QtGui.QDrag(self)
# put our MimeData
drag.setMimeData(mimeData)
# set its Pixmap
drag.setPixmap(pixmap)
# shift the Pixmap so that it coincides with the cursor position
drag.setHotSpot(e.pos())
# start the drag operation
# exec_ will return the accepted action from dropEvent
if drag.exec_(QtCore.Qt.CopyAction | QtCore.Qt.MoveAction) == QtCore.Qt.MoveAction:
print 'moved'
else:
print 'copied'
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)
button = Button('Button', self)
button.move(100, 65)
self.buttons = [button]
self.setWindowTitle('Copy or Move')
self.setGeometry(300, 300, 280, 150)
def dragEnterEvent(self, e):
e.accept()
def dropEvent(self, e):
# get the relative position from the mime data
mime = e.mimeData().text()
x, y = map(int, mime.split(','))
if e.keyboardModifiers() & QtCore.Qt.ShiftModifier:
# copy
# so create a new button
button = Button('Button', self)
# move it to the position adjusted with the cursor position at drag
button.move(e.pos()-QtCore.QPoint(x, y))
# show it
button.show()
# store it
self.buttons.append(button)
# set the drop action as Copy
e.setDropAction(QtCore.Qt.CopyAction)
else:
# move
# so move the dragged button (i.e. event.source())
e.source().move(e.pos()-QtCore.QPoint(x, y))
# set the drop action as Move
e.setDropAction(QtCore.Qt.MoveAction)
# tell the QDrag we accepted it
e.accept()
if __name__ == '__main__':
app = QtGui.QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
Vielen Dank für die wunderbare Antwort. Allerdings habe ich noch einen Zweifel, warum ich den Knopf auf e.pos() - QtCore.QPoint (x, y) verschiebe. Gibt e.pos() selbst nicht die Position an, an die es fallen soll? . Und nicht mimeData gibt die Position des Cursors, weil Sie es auf ex() und ey() gesetzt haben, wobei e die Position der Maus ist, und wenn ich sie ablege, werden nicht sowohl e.pos() als auch QtCore.QPoint (x, y). Entschuldigung für mein Noobness. – Manoj
@Manoj: 'x' und' y' aus dem 'Mime' sind _lokale Position_ des Cursors in Bezug auf die Schaltfläche. 'e.pos()' ist die aktuelle Position des Cursors auf dem Widget ('Beispiel'). Wenn Sie auf die Schaltfläche zu 'e.pos()' wechseln, wird die obere linke Ecke der Schaltfläche an diese Position verschoben. Zum Beispiel haben Sie den Knopf in der Mitte des Knopfes gewählt. Und wenn Sie mit nur 'e.pos()' zur neuen Cursorposition gehen, wird die Schaltfläche nicht so platziert, wie Sie sie ausgewählt haben, sondern verschoben. 'x, y' korrigieren Sie diese Verschiebung, indem Sie den oberen linken Teil der Taste so einstellen, dass der Cursor nach dem Ablegen an der gleichen Position ist. – Avaris
@Manoj: Ich denke, Ihre Verwirrung kommt von 'e.x()/e.y()' vs 'e.pos()' im Code. Der Teil, in dem ich 'e.x()/e.y()' hole, ist das 'mouseMoveEvent' des' Buttons'. Sie sind also relativ zu der Schaltfläche ("0,0" ist die obere linke). Wo als 'e.pos()' im 'dropEvent' von' Example'. Die Position, die es geben wird, ist die relative Position des Cursors in Bezug auf "Beispiel". – Avaris