2012-08-31 67 views
7

我真的很想找到一种方法来做到这一点。说我在一个小部件的窗口实现一个按钮很简单:在PyQt中拖动/移动QPushButton

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

我可以用self.button.move(x,y)走动父控件区域的初始点,我可以通过e.x()e.y()得到mousePressEvent(self, e)鼠标事件,这样按钮移动到我点击的任何位置,但我似乎无法将所有这些放在一起拖放到框架中。

说明:在阅读拖放的“真实”含义之后,那不是我所需要的。我只是希望能够用鼠标移动一个小工具,这与您在冰箱上移动磁铁的方式非常相似。

+1

@Eric在他的回答中提出了一个非常好的观点。您能否澄清这个问题,您是否想要真正的拖放事件......或者只是简单地用鼠标移动按钮 – jdi

+1

根据您打算做的事情 - 我会查看QGraphicsView框架。你正在尝试做什么(虚拟磁铁板)将很容易完成。 –

回答

10

这里是还支持正常的点击信号对可移动按钮的例子:

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,我检查整体移动是否大于至少一个微小的数额。如果是,那么这是一个阻力,我们忽略了正常事件不会产生“点击”信号。否则,我们允许普通事件处理程序产生点击。

+0

This在此期间应该给我足够的咀嚼。谢谢! – RodericDay

+0

不客气!不要忘记接受答案,如果它解决了你的问题! – jdi

+0

我很犹豫导致我最喜欢的答案是使用QGraphicsScene,但这个解决方案是我问的确切问题的更好答案。干得好! – RodericDay

2

这取决于你正在尝试做什么。如果你试图做实际的“拖动&下降”,你会错误的。你所做的只是在其父母的X,Y坐标空间中移动按钮。它从来没有实际调用任何拖放事件,这些完全不同。

你应该通过这里的阻力&降文档阅读:

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

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

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

+0

任何想法,我可以找到一个很好的例子遵循? 我不介意通过拖动彩色矩形或其他东西。出于某种原因,“QDrag”实例的概念对我来说似乎过于复杂,好像它的目的是将文件夹拖入目录或其他东西。 – RodericDay

+0

是的,这是它的主要观点。我想问题是,你的目标是什么? –

+0

我的最终目标是能够通过导入* .bmps 来模拟游戏板。在短期内,我希望能够移动包含Pixmap的QLabel对象,如棋盘上的棋子。但没有任何逻辑或自动放置区域。只是在屏幕上的图像。 我能想到的最好的比喻是冰箱磁铁。我想要虚拟冰箱磁铁。 – RodericDay