2012-08-31 16 views
7

Sto davvero cercando di capire come farlo. Dire che implementare un pulsante in modo molto semplice in una finestra widgetTrascinamento/spostamento di un QPushButton in PyQt

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

posso spostare il suo punto di inizializzazione intorno all'area del widget genitore utilizzando self.button.move(x,y), e posso ottenere gli eventi del mouse da mousePressEvent(self, e) via e.x() e e.y(), in modo che il pulsante si sposta ovunque io clic, ma non riesco a mettere insieme tutto questo in un framework drag and drop.

Precisazione: dopo aver letto il significato "vero" di Trascina/Rilascia, non è quello che mi serve. Voglio solo essere in grado di spostare un widget con il mio mouse, in modo molto simile al modo in cui sposti i magneti su un frigorifero.

+1

@Eric è un ottimo punto nella sua risposta. Potresti chiarire questa domanda se vuoi veri trascini e rilasciare eventi ... o semplicemente essere in grado di spostare il pulsante con il mouse – jdi

+1

In base a ciò che intendi fare - Vorrei esaminare QGraphicsView struttura. Quello che stai cercando di fare (lavagna magnetica virtuale) sarebbe molto facilmente realizzato da quello. –

risposta

10

Ecco un esempio di un pulsante mobile che supporta ancora il normale segnale di click correttamente:

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

Nel mousePressEvent I record sia la posizione di partenza iniziale, e una posizione che andranno aggiornati durante il trascinamento.

Nel mouseMoveEvent, ottengo l'offset corretto del widget da cui è stato fatto clic su dove si trova l'origine effettiva, in modo che lo spostamento sia accurato.

Nel mouseReleaseEvent, controllo per vedere se la mossa complessiva è stata maggiore di almeno una piccola quantità. Se lo era, allora era un trascinamento e ignoriamo l'evento normale per non produrre un segnale "cliccato". Altrimenti, consentiremo al normale gestore di eventi di produrre il clic.

+0

Questo dovrei darmi abbastanza da masticare nel frattempo. Grazie! – RodericDay

+0

Siete i benvenuti! Non dimenticare di accettare la risposta se ha risolto il tuo problema! – jdi

+0

Ero titubante perché la risposta che mi è piaciuta di più è l'utilizzo di QGraphicsScene, ma questa soluzione è la risposta migliore alla domanda esatta che ho posto. Ecco qui! – RodericDay

2

Dipende da ciò che si sta tentando di fare. Se stai cercando di eseguire "Trascorri & Drop", stai sbagliando. Quello che stai facendo è semplicemente spostare il pulsante nel suo spazio di coordinate X, Y all'interno del suo genitore. Non sta mai invocando eventi Drag/Drop, questi sono completamente diversi.

Si dovrebbe leggere attraverso la documentazione drag drop & qui:

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

Invece di spostare il pulsante all'interno del mousePressEvent, sarà necessario creare un nuovo oggetto QDrag ed eseguirlo. Puoi renderlo simile al tuo pulsante scattando un'istantanea del tuo pulsante usando il metodo QPixmap :: grabWidget e assegnandolo all'istanza QDrag usando il metodo QDrag :: setPixmap.

Evento se tutto ciò che stai tentando di fare è spostare il widget nello spazio genitore, ti consiglio di utilizzare questo framework e di accettare semplicemente l'evento di rilascio per il tuo pulsante. Quindi non innescare un mucchio di ridisegni inutili.

+0

qualche idea dove potrei trovare un buon esempio da seguire? Non mi dispiacerebbe iniziare trascinando un rettangolo colorato o qualcosa del genere. L'idea di un'istanza "QDrag" mi sembra eccessivamente complessa per qualche motivo, come se lo scopo fosse il trascinamento di una cartella in una directory o qualcosa del genere. – RodericDay

+0

Sì, questo è il punto principale.Credo che la domanda sia: qual è il tuo obiettivo? –

+0

Il mio obiettivo finale è quello di essere in grado di simulare un tabellone di gioco importando * .bmps A breve termine, voglio essere in grado di spostare oggetti QLabel contenenti una Pixmap in giro, come pezzi di scacchi su una tavola. Ma senza alcuna logica o zone di rilascio automatico. Solo immagini su uno schermo. La migliore analogia a cui riesco a pensare sono i magneti per il frigo. Voglio dei magneti per il frigo virtuale. – RodericDay