Efficient way to move QGraphicItems inside QGraphicsScene

时间秒杀一切 提交于 2019-12-24 14:33:36

问题


I am developing a video player using pyqt5. I am using QGraphicsVideoItem inside a scene. On top of this videoitem, I also need to have some polygons that move around the scene on each new frame. They track things in the video. Ideally I wan't to get them to move with 30 fps. I did a test run, where I moved 1 polygon by 1 pixel at a speed of 30 fps. I did this with the setPos() function in the QGraphicsPolygonItem. This works, but it is very wonky and each time the polygon you can see it flashing white before being repainted. I think this happens because I am moving it too quickly. Also, this action is running in parallel in a thread.

What I want to know is if there is a way move the polygon the same way it moves when you turn on the "QGraphicsItem.ItemIsSelectable" and "QGraphicsItem.ItemIsMovable" flags and move the item manually. This is very smooth and is what I would like to achieve.

I also tried leaving the points as stationary and instead moving the QGraphicsVideoitem around, this kinda worked (the move was steadier and there was no flashing white) but I could not get the scene to be centered on the videoItem. I tried using "setFocus", but this did not work.

Thank you.


回答1:


In these cases it is not advisable to move the item in each frame pixel by pixel, it is better to move every n frames so that the movement is smooth since the route must be interpolated for it can be used QVariantAnimation, in the following example the polygon randomly every 300ms.

import random
from PyQt5 import QtCore, QtGui, QtWidgets

class GraphicsPolygonItem(QtWidgets.QGraphicsPolygonItem):
    def moveTo(self, next_pos, duration=250):
        self._animation = QtCore.QVariantAnimation(
            duration = duration,
            valueChanged = self.setPos,
            startValue = self.pos(),
            endValue = next_pos)
        self._animation.start(QtCore.QAbstractAnimation.DeleteWhenStopped)

class GraphicsView(QtWidgets.QGraphicsView):
    def __init__(self, parent=None):
        super(GraphicsView, self).__init__(parent)
        _scene = QtWidgets.QGraphicsScene(QtCore.QRectF(-250, -250, 500, 500), self)
        self.setScene(_scene)
        self.scene().addRect(self.sceneRect(), brush=QtGui.QBrush(QtCore.Qt.green))
        polygon = QtGui.QPolygonF()
        polygon << QtCore.QPointF( 10, 10 ) << QtCore.QPointF( 0, 90 ) \
                << QtCore.QPointF( 40, 70 ) << QtCore.QPointF( 80, 110 ) \
                << QtCore.QPointF( 70, 20 )

        self._interval = 300

        self.poly_item = GraphicsPolygonItem(polygon)
        self.poly_item.setBrush(QtGui.QBrush(QtCore.Qt.red))
        self.scene().addItem(self.poly_item)
        timer = QtCore.QTimer(self, interval=self._interval, timeout=self.on_timeout)
        timer.start()

    def on_timeout(self):
        p = QtCore.QPointF(
            random.randint(self.sceneRect().left(), self.sceneRect().right()), 
            random.randint(self.sceneRect().top(), self.sceneRect().bottom()))
        self.poly_item.moveTo(p, self._interval)

if __name__ == '__main__':
    import sys
    app = QtWidgets.QApplication(sys.argv)
    w = GraphicsView()
    w.resize(720, 720)
    w.show()
    sys.exit(app.exec_())


来源:https://stackoverflow.com/questions/53807573/efficient-way-to-move-qgraphicitems-inside-qgraphicsscene

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!