PyQt-不重绘所有内容的动画



所以我试图在PyQt中学习动画,在我可以在线找到的所有示例中,它们似乎都使用self.update()self.repaint()方法来增加动画。这意味着基本上代码必须擦除,然后为每一帧重新绘制整个小部件,即使我打算动画的大部分内容都是静态的。

例如下面的代码,这将生成一个循环进度饼图。重要的一点是ProgressMeter(第一类)下的paint()方法:对于动画中的每一帧,此示例绘制背景、实际进度饼图和百分比指示器。

如果我将代码更改为类似的代码

if self.angle > 120:
    # do not draw background

则在120帧之后不再绘制背景。

这似乎非常低效,因为(逻辑上)背景应该只画一次,不是吗?

对于这样的动画,你有什么建议?

附录:我在这个网站上潜伏了很多例子和代码,但已经很久没有发布了。如果我没有正确遵守礼仪等,请告诉我。

import sys
from PyQt4 import QtGui, QtCore

class ProgressMeter(QtGui.QGraphicsItem):
    def __init__(self, parent):
        super(ProgressMeter, self).__init__()
        self.parent = parent
        self.angle = 0
        self.per = 0
    def boundingRect(self):
        return QtCore.QRectF(0, 0, self.parent.width(),
                             self.parent.height())
    def increment(self):
        self.angle += 1
        self.per = int(self.angle / 3.6)
        if self.angle > 360:
            return False
        else:
            return True
    def paint(self, painter, option, widget):
        self.drawBackground(painter, widget)
        self.drawMeter(painter, widget)
        self.drawText(painter)
    def drawBackground(self, painter, widget):
        painter.setRenderHint(QtGui.QPainter.Antialiasing)
        painter.setPen(QtCore.Qt.NoPen)
        p1 = QtCore.QPointF(80, 80)
        g = QtGui.QRadialGradient(p1 * 0.2, 80 * 1.1)
        g.setColorAt(0.0, widget.palette().light().color())
        g.setColorAt(1.0, widget.palette().dark().color())
        painter.setBrush(g)
        painter.drawEllipse(0, 0, 80, 80)
        p2 = QtCore.QPointF(40, 40)
        g = QtGui.QRadialGradient(p2, 70 * 1.3)
        g.setColorAt(0.0, widget.palette().midlight().color())
        g.setColorAt(1.0, widget.palette().dark().color())
        painter.setBrush(g)
        painter.drawEllipse(7.5, 7.5, 65, 65)
    def drawMeter(self, painter, widget):
        painter.setPen(QtCore.Qt.NoPen)
        painter.setBrush(widget.palette().highlight().color())
        painter.drawPie(7.5, 7.5, 65, 65, 0, -self.angle * 16)
    def drawText(self, painter):
        text = "%d%%" % self.per
        font = painter.font()
        font.setPixelSize(11)
        painter.setFont(font)
        brush = QtGui.QBrush(QtGui.QColor("#000000"))
        pen = QtGui.QPen(brush, 1)
        painter.setPen(pen)
        # size = painter.fontMetrics().size(QtCore.Qt.TextSingleLine, text)
        painter.drawText(0, 0, 80, 80,
                         QtCore.Qt.AlignCenter, text)

class MyView(QtGui.QGraphicsView):
    def __init__(self):
        super(MyView, self).__init__()
        self.initView()
        self.setupScene()
        self.setupAnimation()
        self.setGeometry(300, 150, 250, 250)
    def initView(self):
        self.setWindowTitle("Progress meter")
        self.setRenderHint(QtGui.QPainter.Antialiasing)
        policy = QtCore.Qt.ScrollBarAlwaysOff
        self.setVerticalScrollBarPolicy(policy)
        self.setHorizontalScrollBarPolicy(policy)
        self.setBackgroundBrush(self.palette().window())
        self.pm = ProgressMeter(self)
        self.pm.setPos(55, 55)
    def setupScene(self):
        self.scene = QtGui.QGraphicsScene(self)
        self.scene.setSceneRect(0, 0, 250, 250)
        self.scene.addItem(self.pm)
        self.setScene(self.scene)
    def setupAnimation(self):
        self.timer = QtCore.QTimeLine()
        self.timer.setLoopCount(0)
        self.timer.setFrameRange(0, 100)
        self.animation = QtGui.QGraphicsItemAnimation()
        self.animation.setItem(self.pm)
        self.animation.setTimeLine(self.timer)
        self.timer.frameChanged[int].connect(self.doStep)
        self.timer.start()
    def doStep(self, i):
        if not self.pm.increment():
            self.timer.stop()
        self.pm.update()

app = QtGui.QApplication([])
view = MyView()
view.show()
sys.exit(app.exec_())

Qt关于QWidget重新绘制插槽的文档中写道:

通过立即调用paintEvent()直接重新绘制小部件,除非更新被禁用或小部件被隐藏。如果需要立即重新绘制,例如在动画期间,我们建议仅使用重新绘制()。在几乎所有情况下,update()都更好,因为它允许Qt优化速度并最大限度地减少闪烁。警告:如果您在函数中调用paint(),而函数本身可能是从paintEvent()调用的,则可能会得到无限递归。update()函数从不引起递归

这应该会给你一个关于何时使用或不重新绘制或更新插槽的答案。

关于制作动画,我建议你也看看Qt4的动画框架或Qt5的动画帧,这是在Qt上制作小部件动画的一种非常强大的方式。

相关内容

  • 没有找到相关文章

最新更新