2012-08-31 63 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