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