2016-11-24 7 views
1

私の考えは、アイテムにスワップアニメーションを実行することです。しかし、最初にアイテムをスワップしてもポジションを維持していますが、すでにスワップされたアイテムを含む他のアニメーションが開始されると、それらのアイテムは元の位置に戻ります。私が間違っていることを教えてください。アニメーションは、次のように:QGraphicsViewでQGraphicsItemのスワップを実行する方法は?

enter image description here

#include <QtCore> 
    #include <QtWidgets> 


    /** 
    * Element to be displayed in QGraphicsView 
    */ 
    class QGraphicsRectWidget : public QGraphicsWidget 
    { 
     Q_OBJECT 
     int m_number; 

    public: 

     void changePosition(QGraphicsRectWidget *other) 
     { 
      setPos(mapToParent(other->x() < x() ? -abs(x() - other->x()) 
                 : abs(x() - other->x()) ,0)); 
     } 

     static int NUMBER; 

     QGraphicsRectWidget(QGraphicsItem *parent = 0) : QGraphicsWidget(parent), m_number(NUMBER) 
     { NUMBER++;} 
     void paint(QPainter *painter, const QStyleOptionGraphicsItem *, 
        QWidget *) Q_DECL_OVERRIDE 
     { 
      painter->fillRect(rect(), QColor(127, 63, 63)); 
      painter->drawText(rect(), QString("%1").arg(m_number), QTextOption(Qt::AlignCenter)); 
     } 

    }; 

    int QGraphicsRectWidget::NUMBER = 1; 


    class MyAnim : public QPropertyAnimation 
    { 
     Q_OBJECT 

     QGraphicsView &pview; // View in which elements must be swapped 
     int i1, i2;   // Indices for elements to be swapped 

    public: 
     MyAnim(QGraphicsView &view, int index1 = 0, int index2 = 1, QObject *par = 0) 
      : QPropertyAnimation(par), pview(view), i1(index1), i2(index2) 
     { 
      QObject::connect(this, SIGNAL(finished()), SLOT(slotOnFinish())); 
     } 

    public slots: 
     /* !!!!!!!!!!!!!!!!!!!!!!! HERE IS THE PROBLEM (brobably) !!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!*/ 
     // Triggered when animation is over and sets position of target element to position of its end value 
     void slotOnFinish() 
     { 
      auto list = pview.items(); 

      static_cast<QGraphicsRectWidget*>(list.at(i1)) 
        ->changePosition(static_cast<QGraphicsRectWidget*>(list.at(i2))); 
     } 
    }; 

    class GraphicsView : public QGraphicsView 
    { 
     Q_OBJECT 
    public: 
     GraphicsView(QGraphicsScene *scene, QWidget *parent = NULL) : QGraphicsView(scene, parent) 
     { 
     } 

    protected: 
     virtual void resizeEvent(QResizeEvent *event) Q_DECL_OVERRIDE 
     { 
      fitInView(scene()->sceneRect()); 
      QGraphicsView::resizeEvent(event); 
     } 
    }; 


    #define SWAP_HEIGHT 75 

    /** 
    * Creates swap animation for items in QGraphicsView 
    */ 
    QParallelAnimationGroup* getSwapAnimation(QGraphicsView &view, int noItem1, int noItem2) 
    { 
     auto list = view.items(); 
     QGraphicsRectWidget *wgt1 = static_cast<QGraphicsRectWidget*>(list.at(noItem1)); 
     QGraphicsRectWidget *wgt2 = static_cast<QGraphicsRectWidget*>(list.at(noItem2)); 

     MyAnim *pupperAnim, *plowerAnim; 
     QParallelAnimationGroup *par = new QParallelAnimationGroup; 

     plowerAnim = new MyAnim(view, noItem1, noItem2); 
     plowerAnim->setTargetObject(wgt2); 
     plowerAnim->setPropertyName("pos"); 
     plowerAnim->setDuration(5000); 
     plowerAnim->setKeyValueAt(1.0/3.0, QPoint(wgt2->x(), wgt1->y() - SWAP_HEIGHT)); 
     plowerAnim->setKeyValueAt(2.0/3.0, QPoint(wgt1->x(), wgt1->y() - SWAP_HEIGHT)); 
     plowerAnim->setEndValue(wgt1->pos()); 


     pupperAnim = new MyAnim(view, noItem2, noItem1); 
     pupperAnim->setTargetObject(wgt1); 
     pupperAnim->setPropertyName("pos"); 
     pupperAnim->setDuration(5000); 
     pupperAnim->setKeyValueAt(1.0/3.0, QPoint(wgt1->x(), wgt2->y() + SWAP_HEIGHT)); 
     pupperAnim->setKeyValueAt(2.0/3.0, QPoint(wgt2->x(), wgt2->y() + SWAP_HEIGHT)); 
     pupperAnim->setEndValue(wgt2->pos()); 

     par->addAnimation(pupperAnim); 
     par->addAnimation(plowerAnim); 
     return par; 
    } 

    int main(int argc, char **argv) 
    { 
     QApplication app(argc, argv); 

     QGraphicsRectWidget *button1 = new QGraphicsRectWidget; 
     QGraphicsRectWidget *button2 = new QGraphicsRectWidget; 
     QGraphicsRectWidget *button3 = new QGraphicsRectWidget; 
     QGraphicsRectWidget *button4 = new QGraphicsRectWidget; 
     button2->setZValue(1); 
     button3->setZValue(2); 
     button4->setZValue(3); 
     QGraphicsScene scene(0, 0, 300, 300); 
     scene.setBackgroundBrush(QColor(23, 0, 0)); 
     scene.addItem(button1); 
     scene.addItem(button2); 
     scene.addItem(button3); 
     scene.addItem(button4); 
     GraphicsView window(&scene); 
     window.setFrameStyle(0); 
     window.setAlignment(Qt::AlignLeft | Qt::AlignTop); 
     window.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
     window.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 


     QList<QGraphicsItem*> items = window.items(); 
     QPoint start(20, 125); 

     for (auto item : items) // Set items in initial position 
     { 
      QGraphicsWidget *wgt = static_cast<QGraphicsWidget*>(item); 
      wgt->resize(50,50); 
      wgt->moveBy(start.x(), start.y()); 
      start.setX(start.x() + 70); 
     } 


     QSequentialAnimationGroup gr; 

     gr.addAnimation(getSwapAnimation(window, 0, 1)); 
     gr.addAnimation(getSwapAnimation(window, 1, 2)); 
     gr.addAnimation(getSwapAnimation(window, 2, 3)); 
     gr.addAnimation(getSwapAnimation(window, 3, 1)); 
     gr.start(); 

     window.resize(300, 300); 
     window.show(); 

     return app.exec(); 
    } 

    #include "main.moc" 

UPD:その目的の

UPDでアニメーションを使用しないでくださいする*:

+1

「UPDは:その目的とアニメーションを使用しないでください」あなたは、アニメーションを使用する必要がありますすることができます。もちろん、それだけ右:) –

+0

@KubaOberうん、しかし考えると、実際にそれを行います「Qt 5.3 Professional C++プログラミング」の著者であり、使用しないように助言されたMax Schleeと話をしましたが、私はこれを使用しないことに決めました。私はアニメーションではできませんが、お尻には大きな痛みがあります。そして、私はすでに解決策を見つけました。 – Vadixem

+1

何が効果的で、どのような結果が最も読みやすいコードになるかを使用します。あなたがたくさんのアイテムをアニメーション化しない限り、パフォーマンスが重要な役割を果たしているのではないかと私は考えています。そうするなら、 'QAbstractAnimation'で始まり、' QObject'アイテムなどを持つオーバーヘッドを避ける 'QGraphicsItemPositionAnimation'を実装することができます:) –

答えて

1

あなたのアニメーションは、アイテムの位置を保持し、前のUPDを忘れ関与アニメーションが作成された時点で。 2番目のアニメーションが実行されるまでに、この情報は無効です。

開始時にキーポイントの値を更新するには、アニメーションを再設計する必要があります。また、アニメートされたアイテムが一定のスピードで、または少なくともあなたが完全にコントロールできるスピードで動作するようにすることもできます。例えば

// https://github.com/KubaO/stackoverflown/tree/master/questions/scene-anim-swap-40787655 
#include <QtWidgets> 
#include <cmath> 

class QGraphicsRectWidget : public QGraphicsWidget 
{ 
public: 
    void paint(QPainter *painter, const QStyleOptionGraphicsItem *, QWidget *) override 
    { 
     painter->fillRect(rect(), Qt::blue); 
     painter->setPen(Qt::yellow); 
     painter->drawText(rect(), QString::number(zValue()), QTextOption(Qt::AlignCenter)); 
    } 
}; 

class SwapAnimation : public QPropertyAnimation 
{ 
    QPointer<QObject> other; 
    qreal offset; 
    QPoint propertyOf(QObject *obj) { 
     return obj->property(propertyName().constData()).toPoint(); 
    } 
    void updateState(State newState, State oldState) override { 
     if (newState == Running && oldState == Stopped) { 
     auto start = propertyOf(targetObject()); 
     auto end = propertyOf(other); 
     auto step1 = fabs(offset); 
     auto step2 = QLineF(start,end).length(); 
     auto steps = 2.0*step1 + step2; 
     setStartValue(start); 
     setKeyValueAt(step1/steps, QPoint(start.x(), start.y() + offset)); 
     setKeyValueAt((step1+step2)/steps, QPoint(end.x(), end.y() + offset)); 
     setEndValue(end); 
     setDuration(10.0 * steps); 
     } 
     QPropertyAnimation::updateState(newState, oldState); 
    } 
public: 
    SwapAnimation(QObject *first, QObject *second, qreal offset) : other(second), offset(offset) { 
     setTargetObject(first); 
     setPropertyName("pos"); 
    } 
}; 

QParallelAnimationGroup* getSwapAnimation(QObject *obj1, QObject *obj2) 
{ 
    auto const swapHeight = 75.0; 
    auto par = new QParallelAnimationGroup; 
    par->addAnimation(new SwapAnimation(obj2, obj1, -swapHeight)); 
    par->addAnimation(new SwapAnimation(obj1, obj2, swapHeight)); 
    return par; 
} 

int main(int argc, char **argv) 
{ 
    QApplication app(argc, argv); 

    QGraphicsScene scene(0, 0, 300, 300); 
    QGraphicsRectWidget buttons[4]; 
    int i = 0; 
    QPointF start(20, 125); 
    for (auto & button : buttons) { 
     button.setZValue(i++); 
     button.resize(50,50); 
     button.setPos(start); 
     start.setX(start.x() + 70); 
     scene.addItem(&button); 
    } 

    QSequentialAnimationGroup gr; 
    gr.addAnimation(getSwapAnimation(&buttons[0], &buttons[1])); 
    gr.addAnimation(getSwapAnimation(&buttons[1], &buttons[2])); 
    gr.addAnimation(getSwapAnimation(&buttons[2], &buttons[3])); 
    gr.addAnimation(getSwapAnimation(&buttons[3], &buttons[1])); 
    gr.start(); 

    QGraphicsView view(&scene); 
    view.setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    view.setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff); 
    view.resize(300, 300); 
    view.show(); 
    return app.exec(); 
} 
+0

ありがとうございました! アニメーションを使わずに見つけました。 希望があれば便利です! – Vadixem

関連する問題