PyQt4 - 拖放
Posted
技术标签:
【中文标题】PyQt4 - 拖放【英文标题】:PyQt4 - Drag and Drop 【发布时间】:2013-01-01 23:29:43 【问题描述】:嘿,我一直在阅读 tutorial 以了解 PyQt4 中的拖放方法。但是我无法理解以下几点。如果 somepne 能让我更清楚,那就太好了。
def mouseMoveEvent(self, e): //class Button
mimeData = QtCore.QMimeData()
drag = QtGui.QDrag(self)
drag.setMimeData(mimeData)
drag.setHotSpot(e.pos() - self.rect().topLeft())
dropAction = drag.start(QtCore.Qt.MoveAction)
def dropEvent(self, e): //class Example
position = e.pos()
self.button.move(position)
e.setDropAction(QtCore.Qt.MoveAction)
e.accept()
为什么有一个单独的 self.button.move() 和 e.setDropAction() self.button.move() 实际上不移动按钮本身?有人可以解释一下 drag.setHotSpot 和 drag.start() 的作用吗?谢谢。
【问题讨论】:
【参考方案1】:那个教程已经严重过时了。自 Qt 4.3 以来,QDrag.start
已过时。应该改用QDrag.exec_
。
从exec
的文档中可以看出,它有一个返回值。 dropEvent
中的 setDropAction
确定此值。它不执行移动。这就是您需要self.button.move()
来进行实际移动的原因。那么,setDropAction
的意义何在?你可能需要知道你做了什么样的拖拽操作。想象一下,您正在两个列表小部件之间实现拖放。如果您执行了移动操作,这意味着您需要从源小部件中删除该项目并在目标中创建一个。如果是复制操作,可以保留原件,只在目标中创建一个副本。
setHotSpot
/hotSpot
与QDrag
的setPixmap
相关。您可以在拖动项目时显示QPixmap
。 hotSpot
确定像素图的定位。像素图的位置将使得光标位于相对于像素图左上角的hotSpot
。因此,在该教程的情况下,它是毫无意义的,因为没有要显示的像素图。
这里是该教程的一些修改和更新版本。希望我已经包含了足够多的 cmets。您可以使用Right-Click
移动或使用Shift + Right-Click
复制:
#!/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_()
【讨论】:
感谢您的精彩回答。但是我仍然有疑问,为什么要将按钮移动到 e.pos() - QtCore.QPoint(x , y) 。 e.pos() 本身是否不将位置指定给应该丢弃的位置? .并且 mimeData 没有给出光标的位置,因为您已将其设置为 ex() 和 ey(),其中 e 是鼠标的位置,当我放下它时,不会同时显示 e.pos() 和 QtCore.QPoint (x , y) 。对不起我的菜鸟。 @Manoj:x
和来自mime
的y
是光标相对于按钮的本地位置。 e.pos()
将是光标在小部件上的实际位置 (Example
)。如果您要将按钮移动到e.pos()
,它会将按钮的左上角移动到该位置。例如,您选择了按钮中间的按钮。如果您只使用e.pos()
移动到新的光标位置,按钮将不会按照您拾取的方式放置,而是移动。 x,y
通过调整按钮的左上角来纠正这种偏移,使光标在放置后位于同一位置。
@Manoj:我猜你的困惑来自代码中的e.x()/e.y()
和e.pos()
。我得到e.x()/e.y()
的部分是Button
的mouseMoveEvent
。所以它们是相对于按钮的(0,0
是左上角)。其中e.pos()
在dropEvent
的Example
中。它将给出的位置将是光标相对于Example
的相对位置。
是的,我现在明白了,感谢您的宝贵时间。
如果您也可以帮助我处理这段代码,那就太好了。 ***.com/questions/14606192/… 。很抱歉发送垃圾邮件。【参考方案2】:
Avaris 的答案适用于 PyQt5 和 Python 3。
#!/usr/bin/python
# -*- coding: utf-8 -*-
# Adapted for PyQt5 and Python 3 from Avaris' answer to
# https://***.com/questions/14395799/pyqt4-drag-and-drop
import sys
from PyQt5.QtWidgets import QPushButton, QWidget, QApplication
from PyQt5.QtCore import Qt, QMimeData, QPoint
from PyQt5.QtGui import QDrag, QPixmap, QPainter, QColor
class Button(QPushButton):
def mouseMoveEvent(self, e):
if e.buttons() != Qt.RightButton:
return
# write the relative cursor position to mime data
mimeData = 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 = QWidget.grab(self)
# below makes the pixmap half transparent
painter = QPainter(pixmap)
painter.setCompositionMode(painter.CompositionMode_DestinationIn)
painter.fillRect(pixmap.rect(), QColor(0, 0, 0, 127))
painter.end()
# make a QDrag
drag = 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_(Qt.CopyAction | Qt.MoveAction) == Qt.MoveAction:
print('moved')
else:
print('copied')
def mousePressEvent(self, e):
QPushButton.mousePressEvent(self, e)
if e.button() == Qt.LeftButton:
print('press')
class Example(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() & 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()-QPoint(x, y))
# show it
button.show()
# store it
self.buttons.append(button)
# set the drop action as Copy
e.setDropAction(Qt.CopyAction)
else:
# move
# so move the dragged button (i.e. event.source())
e.source().move(e.pos()-QPoint(x, y))
# set the drop action as Move
e.setDropAction(Qt.MoveAction)
# tell the QDrag we accepted it
e.accept()
if __name__ == '__main__':
app = QApplication(sys.argv)
ex = Example()
ex.show()
app.exec_()
【讨论】:
以上是关于PyQt4 - 拖放的主要内容,如果未能解决你的问题,请参考以下文章