【问题标题】:Dragging/Moving a QPushButton in PyQt在 PyQt 中拖动/移动 QPushButton
【发布时间】:2012-08-31 17:07:05
【问题描述】:

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

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

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

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

【问题讨论】:

  • @Eric 在他的回答中提出了一个很好的观点。您能否澄清这个问题,您是否想要真正的拖放事件......或者只是能够用鼠标移动按钮
  • 根据您的意图 - 我会研究 QGraphicsView 框架。您正在尝试做的事情(虚拟磁铁板)很容易通过它来完成。

标签: python pyqt pyqt4


【解决方案1】:

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

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_()

mousePressEvent 中,我记录了初始起始位置以及将在整个拖动过程中更新的位置。

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

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

【讨论】:

  • 这应该足以让我同时咀嚼。谢谢!
  • 不客气!如果它解决了您的问题,请不要忘记接受答案!
  • 我很犹豫,因为我最喜欢的答案是使用 QGraphicsScene,但这个解决方案是我提出的确切问题的更好答案。给你!
  • 我没有意识到你甚至想要一个 QGraphicsScene 解决方案。您的初始示例显示了一个 QPushButton。如果我知道的话,我可以给出一个 QGraphics 版本。它实际上并没有太大的不同。您只是使用 QGraphicsScene 事件,并使用场景位置而不是全局位置
  • 是的,我意识到了。我试图想得太远/以我认为最有利于答案的方式表达问题(甚至不知道 QGraphicsScene),然后我陷入了如何最好地帮助一个尴尬的决定程序员将来有我的问题。希望我们在这里进行的这个小小的讨论能够解决它。
【解决方案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 实例,从而使其看起来像您的按钮。

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

【讨论】:

  • 知道在哪里可以找到一个很好的例子吗?我不介意从拖动彩色矩形或其他东西开始。出于某种原因,“QDrag”实例的想法对我来说似乎过于复杂,就好像它的目的是将文件夹拖到目录中一样。
  • 是的,这就是它的重点。我想问题是,你的目标是什么?
  • 我的最终目标是能够通过导入 *.bmps 来模拟游戏板。在短期内,我希望能够移动包含 Pixmap 的 QLabel 对象,就像棋盘上的棋子一样。但没有任何逻辑或自动放置区。只是屏幕上的图像。我能想到的最好的比喻是冰箱磁铁。我想要虚拟冰箱磁铁。
  • 啊,好吧,然后是的,忽略 QDrag 的东西 - 你用错误的小部件来处理它。对于您想要做的事情,您应该查看 QGraphicsView 框架。在此处查看此问题和答案:stackoverflow.com/questions/12213391/…
猜你喜欢
  • 2018-10-01
  • 2020-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-01-08
  • 2013-10-04
  • 1970-01-01
相关资源
最近更新 更多