【问题标题】:PyQt4 - Drag and DropPyQt4 - 拖放
【发布时间】: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() 的作用吗?谢谢。

【问题讨论】:

    标签: python qt button drag-and-drop pyqt4


    【解决方案1】:

    那个教程已经严重过时了。自 Qt 4.3 以来,QDrag.start 已过时。应该改用QDrag.exec_

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

    setHotSpot/hotSpotQDragsetPixmap 相关。您可以在拖动项目时显示QPixmaphotSpot 确定像素图的定位。像素图的位置将使得光标位于相对于像素图左上角的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 和来自mimey 是光标相对于按钮的本地位置e.pos() 将是光标在小部件上的实际位置 (Example)。如果您要将按钮移动到e.pos(),它会将按钮的左上角移动到该位置。例如,您选择了按钮中间的按钮。如果您只使用e.pos() 移动到新的光标位置,按钮将不会按照您拾取的方式放置,而是移动。 x,y 通过调整按钮的左上角来纠正这种偏移,使光标在放置后位于同一位置。
    • @Manoj:我猜你的困惑来自代码中的e.x()/e.y()e.pos()。我得到e.x()/e.y() 的部分是ButtonmouseMoveEvent。所以它们是相对于按钮的(0,0 是左上角)。其中e.pos()dropEventExample 中。它将给出的位置将是光标相对于Example 的相对位置。
    • 是的,我现在明白了,感谢您的宝贵时间。
    • 如果您也可以帮助我处理这段代码,那就太好了。 stackoverflow.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://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_()
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2012-01-14
      • 1970-01-01
      • 2011-05-08
      • 1970-01-01
      • 1970-01-01
      • 2020-04-03
      • 1970-01-01
      • 2012-10-19
      相关资源
      最近更新 更多