在 QGraphicsScene 中移动 QGraphicItems 的有效方法
Efficient way to move QGraphicItems inside QGraphicsScene
我正在使用 pyqt5 开发一个视频播放器。我在场景中使用 QGraphicsVideoItem。在这个视频项目之上,我还需要一些多边形在每个新帧上围绕场景移动。他们跟踪视频中的内容。理想情况下,我不想让它们以 30 fps 的速度移动。我做了一个测试 运行,我以 30 fps 的速度将 1 个多边形移动 1 个像素。我使用 QGraphicsPolygonItem 中的 setPos() 函数完成了此操作。这行得通,但它非常不稳定,每次你都可以看到多边形在重新绘制之前闪烁白色。我认为发生这种情况是因为我移动得太快了。此外,此操作 运行 在一个线程中并行进行。
我想知道的是,是否有一种方法可以像您打开 "QGraphicsItem.ItemIsSelectable" 和 "QGraphicsItem.ItemIsMovable" 标志并手动移动项目时那样移动多边形。这是非常顺利的,也是我想要达到的。
我也尝试让点保持静止,而不是四处移动 QGraphicsVideoitem,这有点奏效(移动更稳定,没有闪烁的白色)但我无法让场景以 videoItem 为中心。我尝试使用 "setFocus",但这没有用。
谢谢。
在这些情况下,不建议逐帧移动项目,最好每n帧移动一次,以便移动平滑,因为路线必须插值,可以使用QVariantAnimation,在下面的示例中,多边形每 300 毫秒随机生成一次。
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_())
我正在使用 pyqt5 开发一个视频播放器。我在场景中使用 QGraphicsVideoItem。在这个视频项目之上,我还需要一些多边形在每个新帧上围绕场景移动。他们跟踪视频中的内容。理想情况下,我不想让它们以 30 fps 的速度移动。我做了一个测试 运行,我以 30 fps 的速度将 1 个多边形移动 1 个像素。我使用 QGraphicsPolygonItem 中的 setPos() 函数完成了此操作。这行得通,但它非常不稳定,每次你都可以看到多边形在重新绘制之前闪烁白色。我认为发生这种情况是因为我移动得太快了。此外,此操作 运行 在一个线程中并行进行。
我想知道的是,是否有一种方法可以像您打开 "QGraphicsItem.ItemIsSelectable" 和 "QGraphicsItem.ItemIsMovable" 标志并手动移动项目时那样移动多边形。这是非常顺利的,也是我想要达到的。
我也尝试让点保持静止,而不是四处移动 QGraphicsVideoitem,这有点奏效(移动更稳定,没有闪烁的白色)但我无法让场景以 videoItem 为中心。我尝试使用 "setFocus",但这没有用。
谢谢。
在这些情况下,不建议逐帧移动项目,最好每n帧移动一次,以便移动平滑,因为路线必须插值,可以使用QVariantAnimation,在下面的示例中,多边形每 300 毫秒随机生成一次。
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_())