0

我目前正在尝试在 QAnimation 框架的帮助下使用 Qt 构建幻灯片查看器。我在移动照片的同时更改照片的大小时遇到​​问题,因为在幻灯片中更改照片在移动时的大小似乎会影响其轨迹。

具体来说,我正在尝试为一组照片设置动画,使它们在窗口的水平中心线上从右到左连续移动,同时改变大小。基本上,它是一种“鱼眼”效果,当照片向窗口中心移动时会变大,然后在移开时缩小回原来的大小。

在任何给定时间,窗口只会显示 3 张照片(加上 1 张离开左侧窗口的照片)。假设从左到右排序的 3 张照片分别标记为 P1、P2、P3。考虑一张照片,最右边的照片 P3。随着 P3 从窗口右侧向中心移动,它的大小应逐渐增加并在窗口中心达到最大大小。随着它继续向左移动并最终退出窗口,它的大小应该减小回原来的值。

如果我只是移动照片而不调整它们的大小,我当前的实现是有效的。当同时移动和缩放图像时,照片不再在窗口中心水平移动。照片的大小似乎已正确缩放。

我当前的实现依赖于 QPropertyAnimation 类来执行动画。我正在使用 Python 和 Qt 的 PySide 绑定编写程序,但是 C++ 或 PyQt 代码中的解决方案很好。我只会将它们翻译成 Python 和 PySide。

相关代码如下:

def animate(self, items):
'''@params: items The photos to animate'''
    logging.debug('Creating %d animation objects', len(items))
    self.animationGroup.clear()
    for i, item in enumerate(items):
        self.animatePosition(item, i, len(items))
        self.animateScale(item, i)
    QTimer.singleShot(START_DELAY, self.animationGroup.start)    

def animatePosition(self, item, index, numItems):
    isLastItem = (index == numItems - 1)
    isFirstItem = (index == 0)

    posAnimation = QPropertyAnimation(item, 'position')
    posAnimation.setDuration(SLIDE_INTERVAL)
    posAnimation.setStartValue(item.pos())
# I've tried changing dh depending on the scale of the current image with limited success.
dh = 0 
    if isLastItem:
        posAnimation.setEndValue(item.pos() - QPointF(slideshow.RIGHT_MARGIN + slideshow.STANDARD_SLIDE_WIDTH, dh))
    elif isFirstItem:
        posAnimation.setEndValue(item.pos() - QPointF(slideshow.LEFT_MARGIN + slideshow.STANDARD_SLIDE_WIDTH, dh))
    else:
        posAnimation.setEndValue(item.pos() - QPointF(slideshow.IMAGE_GAP + slideshow.STANDARD_SLIDE_WIDTH, dh))
    posAnimation.setEasingCurve(QEasingCurve.OutExpo)
    self.animationGroup.addAnimation(posAnimation)

def animateScale(self, item, index):
    if self.animatedView is not None:
        scaleAnimation = QPropertyAnimation(item, 'slideScale')
        scaleAnimation.setDuration(SLIDE_INTERVAL)
        scaleAnimation.setStartValue(item.scale())
        endScale = self.getSlideScale(index - 1)
        scaleAnimation.setEndValue(endScale)
        scaleAnimation.setEasingCurve(QEasingCurve.OutExpo)
        self.animationGroup.addAnimation(scaleAnimation)

我知道通常照片必须在应用缩放变换之前移回原点,然后移回其轨迹上的下一个位置。我怀疑用于缩放照片的 QPropertyAnimation 正在应用于翻译后的照片并因此影响其轨迹,但我可能是错的,因为我在过去 1-2 周才开始使用 Qt。

有谁知道我如何让 QPropertyAnimation 知道另一个动画正在发生?或者任何人都可以提出一种不同的方法(不一定涉及 QPropertyAnimation)来解决上述问题?

提前感谢任何回复。

4

1 回答 1

0

我假设您正在使用 QGraphicsView 框架(如果您发布了一个最小的、正在运行的示例程序,那么理解和调试您的问题会容易得多)。

我建议使用QGraphicsWidgets并直接为其“几何”属性设置动画(编辑:我在这里错了,这不起作用)。

您需要在不使用两个 QPropertyAnimation 的情况下同时更改大小和位置。最简单的解决方案很可能是继承QVariantAnimation(甚至是 QVariantAnimation)并updateCurrentValue()适当地实现。我想我会插入一个 QRectF 从中提取位置和大小/比例,否则你当然可以插入一个浮点数(这意味着你将有更多的插值代码自己做,但它不必计算比例规模)。考虑将所需的比例编组为 QRectF 的大小(例如,通过QSizeF(scale, scale)给构造函数)。这有点骇人听闻,因为 QRectF 不再是/不是/所需的项目几何形状,但其他方面很简单并且效果很好(也适用于缓动曲线)。这是一个有用的片段:

class GeometryAnimation(QtCore.QVariantAnimation):
    def __init__(self, item, parent = None):
        QtCore.QVariantAnimation.__init__(self, parent)
        self._item = item

    def updateCurrentValue(self, value):
        self._item.setPos(value.topLeft())
        self._item.setScale(value.width())

为什么您当前的代码不起作用很难说,取决于“slideScale”属性的实现;如果转换相互作用(我认为这是不受欢迎的行为),那就是原因。

于 2012-04-30T12:53:07.627 回答