Python PyQt: как я могу перемещать виджеты в окне с помощью мыши?

Я новичок в Python. Я нарисовал многоугольник и круг с фиксированными координатами. Теперь я хочу переместить этот многоугольник и обвести мышью в другое место в окне. Пожалуйста, помогите мне, как я могу это сделать?

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

person mrtak    schedule 31.08.2012    source источник


Ответы (2)


Вы должны смотреть в QGraphicsView вместо того, что вы делаете, все это уже встроено.

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

Редактировать: показано, как создать 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_()
person Eric Hulser    schedule 31.08.2012
comment
Спасибо, Эрик, за ценный ответ, но это частично решает мою проблему. На самом деле я хочу нарисовать резервуар для воды, который, как мне кажется, будет нарисован с помощью полилинии, потому что мне нужны три стороны, а не верхняя. И объект «QGraphicsScene» не имеет атрибута «addPolyline». Во-вторых, я хочу заполнить бак в зависимости от моей ценности. Как я могу заполнить резервуар для воды (обозначен синим цветом)? - person mrtak; 02.09.2012
comment
Вы можете управлять объектами в своей сцене — они не обязательно должны быть простыми объектами формы. Я бы начал с просмотра QGraphicsPathItem, который позволяет вам определить любой QPainterPath для рисования с поддержкой заполнения. Для более сложных элементов вы можете создать подкласс любого QGraphicsItem, который закроет вас, и реализовать свой собственный метод paintEvent. - person Eric Hulser; 03.09.2012
comment
Кстати, ярлык для добавления пути - QGraphicsScene.addPath - person Eric Hulser; 03.09.2012
comment
Эрик, я пытался следовать вашим предложениям, но не смог добавить свой код для полилинии, написанный с использованием PainterPath, в QGraphicsScene. Не могли бы вы прислать небольшой код для добавления этого. Во-вторых, как сохранить позиции виджетов, потому что, когда я закрываю окно, все виджеты возвращаются на свои исходные позиции (я хочу сохранить новые позиции виджетов)? - person mrtak; 07.09.2012
comment
Я обновил код примером того, как создать QPainterPath, как у вас. Что касается сохранения позиций, вам нужно будет где-то записать их в настройки — вы можете перебрать свои объекты, выполнив scene.items(), и получить позицию для каждого элемента, выполнив item.pos() - person Eric Hulser; 07.09.2012
comment
Большое спасибо, Эрик, это решение очень помогает мне понять многие вещи. Я использовал paintEvent для создания своих виджетов, теперь я могу напрямую использовать для него QColor. На самом деле, я разрабатываю все эти предметы в статическом окне и исправляю свои предметы. Так как в динамике мне нужно сохранять позиции виджетов. Я обязательно сделаю это упражнение (сохранение элементов) после того, как закончу свой статический графический интерфейс. - person mrtak; 07.09.2012

вдохновленный ответами Эрика, вот код, который анимирует точку, обновляя ее координаты x и 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_())
person dnt2s    schedule 16.02.2017