当窗口大小随绘制事件更改时,启用小部件如何移动?

2024-06-28 19:26:13 发布

您现在位置:Python中文网/ 问答频道 /正文

我正在尝试创建一个小部件来设置线条的动画,当窗口大小改变时,动画总是按大小播放

我知道画家的道路总是一样的,但我没有任何简单的想法去做

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *
class PathAnimation(QPropertyAnimation):
    def __init__(self, path=QPainterPath(), object=None, property=None):
        super().__init__(object, property)
        self.path = path

    def updateCurrentTime(self, currentTime):
        easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
        pt = self.path.pointAtPercent(easedProgress)
        self.updateCurrentValue(pt)
        self.valueChanged.emit(pt)

class DemoB(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(400, 400)
        self.button = QPushButton('test', self)

    def mouseDoubleClickEvent(self, e):
        self.ani = PathAnimation(self.path, self.button, b'pos')
        self.ani.setDuration(2000)
        self.ani.start()

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.begin(self)
        painter.setWindow(0, 0, 400, 400)
        self.path = QPainterPath()
        self.path.cubicTo(QPointF(0, 400), QPointF(200, 0), QPointF(400, 400))

        painter.drawPath( self.path )
        painter.end()

app = QApplication([])
demo = DemoB()
demo.show()
app.exec()

Tags: pathfromimportselfptinitdef动画
1条回答
网友
1楼 · 发布于 2024-06-28 19:26:13

对不起,你的问题有点困惑。如果我理解正确,您希望在每次调整窗口大小时更新路径。
问题在于,每当绘制窗口时,您都会创建一个新的self.path对象,这也会在第一次绘制窗口时发生,因此您为属性创建的QPainterPath对象实际上不会更新

您应该仅在调整窗口大小时更新路径,这在resizeEvent()

然后请记住,您只能从Qt5.13(去年6月发布)更新现有路径,否则您必须创建一个新路径,并确保更新动画的path属性

from PyQt5.QtGui import *
from PyQt5.QtCore import *
from PyQt5.QtWidgets import *

# find if Qt version is >= 5.13
QtVersion = [int(v) for v in QT_VERSION_STR.split('.')]
CanClearPath = QtVersion[0] == 5 and QtVersion[1] >= 13

class PathAnimation(QPropertyAnimation):
    def __init__(self, path=QPainterPath(), object=None, property=None):
        super().__init__(object, property)
        self.path = path

    def updateCurrentTime(self, currentTime):
        easedProgress = self.easingCurve().valueForProgress(currentTime/self.duration())
        pt = self.path.pointAtPercent(easedProgress)
        self.updateCurrentValue(pt)
        self.valueChanged.emit(pt)

class DemoB(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(400, 400)
        self.button = QPushButton('test', self)
        self.path = QPainterPath()
        self.ani = PathAnimation(self.path, self.button, b'pos')
        self.ani.setDuration(2000)

    def mouseDoubleClickEvent(self, e):
        if self.ani.state():
            return
        self.ani.setStartValue(QPointF(0, 0))
        self.ani.start()

    def resizeEvent(self, event):
        if CanClearPath:
            self.path.clear()
        else:
            self.path = QPainterPath()
        rect = self.rect()
        # use the current size to update the path positions
        self.path.cubicTo(rect.bottomLeft(), 
            QPointF(rect.center().x(), 0), rect.bottomRight())
        # update the final value!
        self.ani.setEndValue(rect.bottomRight())
        if not CanClearPath:
            self.ani.path = self.path

    def paintEvent(self, e):
        painter = QPainter(self)
        # no need to begin() a painter if you already gave it its argument
        painter.drawPath(self.path)

if __name__ == '__main__':
    import sys
    app = QApplication(sys.argv)
    demo = DemoB()
    demo.show()
    sys.exit(app.exec())

另一种可能是完全避免QPropertyImation子类,使用从0.01.0的私有属性,为其创建QPropertyImation,然后将其valueChanged信号连接到使用pointAtPercent计算位置的函数,然后移动按钮

class DemoB(QWidget):
    def __init__(self):
        super().__init__()
        self.resize(400, 400)
        self.button = QPushButton('test', self)
        self.path = QPainterPath()
        # create an internal property
        self.setProperty('pathPercent', 0.0)
        self.ani = QPropertyAnimation(self, b'pathPercent')
        self.ani.setEndValue(1.0)
        self.ani.setDuration(2000)
        self.ani.valueChanged.connect(self.updatePosition)

    def mouseDoubleClickEvent(self, e):
        if self.ani.state():
            return
        # reset the property to 0 so that it is restarted from the beginning
        self.setProperty('pathPercent', 0.0)
        self.ani.start()

    def updatePosition(self, pos):
        self.button.move(self.path.pointAtPercent(pos).toPoint())

    def resizeEvent(self, event):
        # recreate/update the current path, based on the new window size.
        if CanClearPath:
            self.path.clear()
        else:
            self.path = QPainterPath()
        rect = self.rect()
        self.path.cubicTo(rect.bottomLeft(), 
            QPointF(rect.center().x(), 0), rect.bottomRight())

    def paintEvent(self, e):
        painter = QPainter(self)
        painter.drawPath(self.path)

相关问题 更多 >