Python PyQt: ¿Cómo puedo mover mis widgets en la ventana con el mouse?

Soy nuevo en Python. He dibujado polígono y círculo con coordenadas fijas. Ahora quiero mover este polígono y un círculo con el mouse a algún otro lugar de la ventana. Por favor guíame, ¿cómo puedo hacerlo?

import sys from PyQt4.QtGui import * from PyQt4.QtCore import * class MyFrame(QWidget): def __init__(self, parent=None): QWidget.__init__(self) def paintEvent(self, event=None): paint=QPainter(self) paint.setPen(QPen(QColor(Qt.green).dark(150),1,Qt.SolidLine)) segColor=QColor(Qt.green).dark(150) paint.setBrush(segColor) paint.setBrushOrigin(QPoint(225,225)) polygon=QPolygon([QPoint(250,175), QPoint(265,175), QPoint(250,190), QPoint(265,190),QPoint(250,175)]) paint.drawPolygon(polygon) paint.setPen(QPen(QColor(Qt.red),1,Qt.SolidLine)) paint.setBrush(QBrush(Qt.NoBrush)) polygon1=QPolygon([QPoint(250,300), QPoint(250,500), QPoint(350,500), QPoint(350,300)]) paint.drawPolyline(polygon1) paint.drawEllipse(50,50,50,50) app=QApplication(sys.argv) f=MyFrame() f.show() app.exec_() 

Deberías mirar en QGraphicsView en lugar de lo que estás haciendo, ya que todo está incorporado.

http://doc.qt.nokia.com/4.7-snapshot/qgraphicsview.html

http://doc.qt.nokia.com/4.7-snapshot/qgraphicsscene.html

 from PyQt4 import QtGui, QtCore class MyFrame(QtGui.QGraphicsView): def __init__( self, parent = None ): super(MyFrame, self).__init__(parent) self.setScene(QtGui.QGraphicsScene()) # add some items x = 0 y = 0 w = 45 h = 45 pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green)) brush = QtGui.QBrush(pen.color().darker(150)) item = self.scene().addEllipse(x, y, w, h, pen, brush) item.setFlag(QtGui.QGraphicsItem.ItemIsMovable) if ( __name__ == '__main__' ): app = QtGui.QApplication([]) f = MyFrame() f.show() app.exec_() 

Edición: Mostrar cómo crear un QPainterPath

 from PyQt4 import QtGui, QtCore class MyFrame(QtGui.QGraphicsView): def __init__( self, parent = None ): super(MyFrame, self).__init__(parent) scene = QtGui.QGraphicsScene() self.setScene(scene) # add some items x = 0 y = 0 w = 45 h = 45 pen = QtGui.QPen(QtGui.QColor(QtCore.Qt.green)) brush = QtGui.QBrush(pen.color().darker(150)) item = scene.addEllipse(x, y, w, h, pen, brush) item.setFlag(QtGui.QGraphicsItem.ItemIsMovable) # create an open path path = QtGui.QPainterPath() path.moveTo(-w, -h) path.lineTo(-w, h) path.lineTo(w, h) path.lineTo(w, -h) clr = QtGui.QColor('blue') clr.setAlpha(120) brush = QtGui.QBrush(clr) pen = QtGui.QPen(QtCore.Qt.NoPen) fill_item = scene.addRect(-w, y, w*2, h, pen, brush) path_item = scene.addPath(path) if ( __name__ == '__main__' ): app = QtGui.QApplication([]) f = MyFrame() f.show() app.exec_() 

inspirado en las respuestas de Eric, aquí hay un código que anima el punto al actualizar sus coordenadas x e y.

 from PyQt5.QtGui import QPen, QBrush, QColor from PyQt5.QtCore import Qt, QTimer from PyQt5.QtWidgets import QGraphicsView, QGraphicsScene, QGraphicsItem, QApplication class GameWindow(QGraphicsView): def __init__( self, parent = None ): super().__init__(parent) self.sx = 635 self.sy = 475 scene = QGraphicsScene(0,0,self.sx,self.sy) self.setScene(scene) self.x = 0 self.y = 0 self.w = 30 self.h = 30 pen = QPen(QColor('dodgerblue')) #pen = QPen(QColor(Qt.green)) brush = QBrush(pen.color()) #brush = QBrush(pen.color().darker(150)) # As opposed to using QPen and QBrush, this colors the periphery only #dot = scene.addEllipse(self.x, self.y, self.w, self.h, QColor('dodgerblue')) self.dot = scene.addEllipse(self.x, self.y, self.w, self.h, pen, brush) self.dot.setFlag(QGraphicsItem.ItemIsMovable) if __name__ == '__main__': import sys fps = 50 refresh_period = 1000/fps # ms app = QApplication(sys.argv) gw = GameWindow() gw.resize(640,480) gw.show() # if the steps match the gw aspect ratio, the dot will move along the main diagonal, # otherwise the dot will drift xstep = 4 ystep = 3 #ystep = xstep * gw.sy / gw.sx def moveDot(): # In place of the next four lines, one can have a function # or a feed from an external source to update gw.x and gw.y gw.x += xstep gw.x %= gw.sx gw.y += ystep gw.y %= gw.sy gw.dot.setRect(gw.x,gw.y,gw.w,gw.h) timer = QTimer() timer.timeout.connect(moveDot) # Comment this line out to be able to click and drag the dot timer.start(refresh_period) sys.exit(app.exec_())