Python PyQt4-拖放

Python PyQt4-拖放,python,qt,button,drag-and-drop,pyqt4,Python,Qt,Button,Drag And Drop,Pyqt4,嘿,为了理解PyQt4中的拖放方法,我一直在学习这个。然而,我无法理解以下几点。如果有人能对我说得更清楚就好了 def mouseMoveEvent(self, e): //class Button mimeData = QtCore.QMimeData() drag = QtGui.QDrag(self) drag.setMimeData(mimeData) drag.setHotSpot(e.pos() - self.rect().topLeft())

嘿,为了理解PyQt4中的拖放方法,我一直在学习这个。然而,我无法理解以下几点。如果有人能对我说得更清楚就好了

 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()的作用吗?谢谢。

那个教程已经严重过时了<代码>QDrag.start已从过时。应该改用

exec
的文档中可以看到,它有一个返回值<
dropEvent
中的code>setDropAction确定此值。它不执行移动。这就是为什么需要一个
self.button.move()
来进行实际移动。那么,
setDropAction
有什么意义呢?你可能需要知道你做了什么样的拖动操作。假设您正在两个列表小部件之间实现拖放。如果您执行了移动操作,这意味着您需要从源窗口小部件中删除该项,并在目标窗口小部件中创建一个。如果是复制操作,则可以保留原始文件,只需在目标中创建副本

sethospot
/
hospot
QDrag的
setPixmap
相关。拖动项目时,可以显示
QPixmap
<代码>热点
确定pixmap的位置。将定位pixmap,使光标位于相对于pixmap左上角的热点处。因此,在该教程中,它是毫无意义的,因为没有要显示的pixmap

这里是该教程的一个稍加修改和更新的版本。希望我的评论足够多。您可以使用
右键单击移动
或使用
Shift+右键单击复制

#!/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_()  

Avaris的答案适用于PyQt5和Python 3

#!/usr/bin/python
# -*- coding: utf-8 -*-

# Adapted for PyQt5 and Python 3 from Avaris' answer to
# https://stackoverflow.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_()

谢谢你的精彩回答。但是我仍然有疑问,为什么要将按钮移动到e.pos()-QtCore.QPoint(x,y)。e.pos()本身,是否给出了应该放置的位置。mimeData没有给出光标的位置,因为你已经将它设置为e.x()和e.y(),其中e是鼠标的位置,当我放下它时,e.pos()和QtCore.QPoint(x,y)不会同时出现。很抱歉,我不知道。@Manoj:
x
y
来自
mime
是光标相对于按钮的本地位置
e.pos()
将是小部件上光标的实际位置(
示例
)。如果要将按钮移动到
e.pos()
,它会将按钮的左上角移动到该位置。例如,您选择了按钮中间的按钮。如果您仅使用
e.pos()
移动到新的光标位置,按钮将不会按您拾取的方式放置,而是移动
x,y
通过调整按钮的左上角来纠正该移位,使光标在落下后处于相同的位置。@Manoj:我猜您的混淆来自代码中的
e.x()/e.y()
vs
e.pos()
。我得到
e.x()/e.y()
的部分是
按钮的
mouseMoveEvent
。因此它们是相对于按钮的(
0,0
位于左上方)。其中作为
e.pos()
示例的
dropEvent
中。它给出的位置将是光标相对于
示例的相对位置。是的,我现在理解了,谢谢你的时间。如果你也能帮我处理这段代码,那将非常好。抱歉发了垃圾邮件。