9

我真的很难找到一种方法来做到这一点。假设我在小部件窗口中非常简单地实现了一个按钮:

self.button = QPushButton("Drag Me", self)

我可以使用 将其初始化点移动到父小部件的区域周围,并且可以通过和self.button.move(x,y)获取鼠标事件,以便按钮移动到我单击的任何位置,但我似乎无法将所有这些放在一起拖放框架中。mousePressEvent(self, e)e.x()e.y()

澄清:在阅读了拖放的“真正”含义之后,这不是我需要的。我只想能够用鼠标移动小部件,这与在冰箱上移动磁铁的方式非常相似。

4

2 回答 2

18

这是一个仍然正确支持正常点击信号的可移动按钮的示例:

from PyQt4 import QtCore, QtGui


class DragButton(QtGui.QPushButton):

    def mousePressEvent(self, event):
        self.__mousePressPos = None
        self.__mouseMovePos = None
        if event.button() == QtCore.Qt.LeftButton:
            self.__mousePressPos = event.globalPos()
            self.__mouseMovePos = event.globalPos()

        super(DragButton, self).mousePressEvent(event)

    def mouseMoveEvent(self, event):
        if event.buttons() == QtCore.Qt.LeftButton:
            # adjust offset from clicked point to origin of widget
            currPos = self.mapToGlobal(self.pos())
            globalPos = event.globalPos()
            diff = globalPos - self.__mouseMovePos
            newPos = self.mapFromGlobal(currPos + diff)
            self.move(newPos)

            self.__mouseMovePos = globalPos

        super(DragButton, self).mouseMoveEvent(event)

    def mouseReleaseEvent(self, event):
        if self.__mousePressPos is not None:
            moved = event.globalPos() - self.__mousePressPos 
            if moved.manhattanLength() > 3:
                event.ignore()
                return

        super(DragButton, self).mouseReleaseEvent(event)

def clicked():
    print "click as normal!"

if __name__ == "__main__":
    app = QtGui.QApplication([])
    w = QtGui.QWidget()
    w.resize(800,600)

    button = DragButton("Drag", w)
    button.clicked.connect(clicked)

    w.show()
    app.exec_()

mousePressEventI 中,记录了初始起始位置和将在整个拖动过程中更新的位置。

在 中mouseMoveEvent,我得到了小部件从单击位置到实际原点位置的适当偏移量,以便移动准确。

在 中mouseReleaseEvent,我检查整体移动是否大于至少一个很小的量。如果是,那么它就是一个拖拽,我们忽略正常事件以不产生“点击”信号。否则,我们允许正常的事件处理程序产生点击。

于 2012-08-31T19:19:18.157 回答
2

这取决于你想要做什么。如果您尝试进行实际的“拖放”,那您就错了。您所做的只是在其父项内的 X、Y 坐标空间中移动按钮。它从未真正调用任何拖放事件,这些是完全不同的。

您应该阅读此处的拖放文档:

http://doc.qt.nokia.com/4.7-snapshot/dnd.html
http://qt-project.org/doc/qt-5.0/qdrag.html

您需要创建一个新的 QDrag 对象并执行它,而不是在 mousePressEvent 中移动按钮。您可以通过使用 QPixmap::grabWidget 方法拍摄按钮的快照并使用 QDrag::setPixmap 方法将其分配给 QDrag 实例,使其看起来像您的按钮。

如果您要做的只是在父空间中移动小部件,我建议您使用此框架并只接受按钮的放置事件。然后你就不会触发一堆不必要的重绘。

于 2012-08-31T17:37:08.110 回答