0

現在、QAnimation フレームワークの助けを借りて、Qt でスライドショー ビューアを構築しようとしています。移動中にスライドショーで写真のサイズを変更すると、その軌跡に影響を与えるように見えるため、同時に移動しながら写真のサイズを変更するのに問題があります。

具体的には、一連の写真をアニメーション化して、ウィンドウの水平中心線を横切って右から左に連続的に移動させながら、同時にサイズを変更しようとしています。基本的には、一種の「魚眼」効果で、ウィンドウの中心に向かって移動すると写真が大きくなり、遠ざかるにつれて元のサイズに戻ります。

任意の時点で、ウィンドウには 3 枚の写真のみが表示されます (さらに左側のウィンドウから出てくる 1 枚の写真)。左から右に並べられた 3 つの写真に、P1、P2、P3 というラベルが付いているとします。1 枚の写真、一番右の写真 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 が翻訳された写真に適用されているため、その軌跡に影響を与えていると思われますが、Qt を使い始めてまだ 1 ~ 2 週間なので、間違っている可能性があります。

別のアニメーションが行われていることを QPropertyAnimation に認識させる方法を知っている人はいますか? または、上記の問題を解決するための別のアプローチ (必ずしも QPropertyAnimation を含む必要はありません) を誰かが提案できますか?

返信ありがとうございます。

4

1 に答える 1

0

QGraphicsView フレームワークを使用していると仮定します (最小限の実行中のサンプル プログラムを投稿すると、問題の理解とデバッグがはるかに簡単になります)。

QGraphicsWidgetsを使用して、その「ジオメトリ」プロパティを直接アニメーション化することをお勧めします(編集: ここで間違っていました。これは機能しません)。

2 つの QPropertyAnimation を使用せずに、サイズと位置を同時に変更する必要があります。おそらく最も簡単な解決策は、QVariantAnimation (または QVariantAnimation)をサブクラス化updateCurrentValue()し、適切に実装することです。位置とサイズ/スケールを抽出する QRectF を補間すると思います。それ以外の場合は、もちろん float を補間することもできます (つまり、自分で行う補間コードがさらに増えることになりますが、スケールを計算する必要がなくなります)。サイズ)。目的のスケールを 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 に答える