Arrastrando / Moviendo un QPushButton en PyQt

Estoy realmente luchando para encontrar una manera de hacer esto. Digamos que implemento un botón muy simplemente en una ventana de widget:

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

Puedo mover su punto de inicialización alrededor del área del widget principal usando self.button.move(x,y) , y puedo obtener eventos del mouse desde mousePressEvent(self, e) través de ex() y ey() , de modo que el botón se mueva donde sea que haga clic, pero parece que no puedo juntar todo esto en un marco de arrastrar y soltar.

Aclaración: Después de leer el significado ‘verdadero’ de Arrastrar y soltar, eso no es lo que necesito. Solo quiero poder mover un widget con mi mouse, muy similar a la forma en que mueves los imanes en una nevera.

Este es un ejemplo de un botón móvil que aún admite la señal de clic normal correctamente:

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

En el mousePressEvent , grabo tanto la posición de inicio inicial como la posición que se actualizará a lo largo del arrastre.

En el mouseMoveEvent , obtengo el desplazamiento correcto del widget desde donde se hizo clic hasta el origen real, de modo que el movimiento sea preciso.

En el mouseReleaseEvent , mouseReleaseEvent si el movimiento general fue mayor que al menos una pequeña cantidad. Si fue así, fue un arrastre e ignoramos el evento normal para no producir una señal de “clic”. De lo contrario, permitimos que el controlador de eventos normal produzca el clic.

Depende de lo que estés tratando de hacer. Si está intentando hacer un “arrastrar y soltar” real, lo está haciendo mal. Lo que está haciendo es simplemente mover el botón en su espacio de coordenadas X, Y dentro de su padre. En realidad, nunca invoca ningún evento de arrastrar y soltar, son completamente diferentes.

Debes leer la documentación de arrastrar y soltar aquí:

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

En lugar de mover el botón dentro del mousePressEvent, deberá crear un nuevo objeto QDrag y ejecutarlo. Puede hacer que se vea como su botón tomando una instantánea de su botón usando el método QPixmap :: grabWidget y asignándolo a la instancia de QDrag usando el método QDrag :: setPixmap.

Evento: si todo lo que está tratando de hacer es mover el widget en el espacio principal, recomendaría usar este marco y solo aceptar el evento drop para su botón. Entonces no disparas un montón de redibujes innecesarios.