Qt 如何在QGraphicsView中执行QGraphicsSitem的交换?

Qt 如何在QGraphicsView中执行QGraphicsSitem的交换?,qt,swap,qgraphicsview,qgraphicswidget,Qt,Swap,Qgraphicsview,Qgraphicswidget,我在这个项目中的想法是对项目执行交换动画。 但问题是,当我第一次对项目执行交换时,它们保持其位置不变,但当其他动画开始时,涉及到已交换的项目,这些项目会返回到其初始位置。请告诉我我做错了什么。动画如下: #包括 #包括 /** *要在QGraphicsView中显示的元素 */ 类QGraphicsRectWidget:公共QGraphicsWidget { Q_对象 整数m_数; 公众: 无效更改位置(QGraphicsRectWidget*其他) { setPos(mapToParent(

我在这个项目中的想法是对项目执行交换动画。 但问题是,当我第一次对项目执行交换时,它们保持其位置不变,但当其他动画开始时,涉及到已交换的项目,这些项目会返回到其初始位置。请告诉我我做错了什么。动画如下:

#包括
#包括
/**
*要在QGraphicsView中显示的元素
*/
类QGraphicsRectWidget:公共QGraphicsWidget
{
Q_对象
整数m_数;
公众:
无效更改位置(QGraphicsRectWidget*其他)
{
setPos(mapToParent(其他->x()x())
:abs(x()-其他->x()),0);
}
静态整数;
QGraphicsRectWidget(QGraphicsSitem*parent=0):QGraphicsWidget(parent),m_编号(number)
{NUMBER++;}
空漆(QPainter*油漆工,const QstyleOptionGraphics现场*,
QWidget*)Q_DECL_覆盖
{
painter->fillRect(rect(),QColor(127,63,63));
painter->drawText(rect(),QString(“%1”).arg(m_编号),QTextOption(Qt::AlignCenter));
}
};
int QGraphicsRectWidget::NUMBER=1;
MyAnim类:公共QPropertyAnimation
{
Q_对象
QGraphicsView&pview;//必须在其中交换元素的视图
int i1,i2;//要交换的元素的索引
公众:
MyAnim(QGraphicsView&view,int index1=0,int index2=1,QObject*par=0)
:QPropertyAnimation(par)、pview(view)、i1(index1)、i2(index2)
{
QObject::connect(这个,信号(finished()),插槽(slotOnFinish());
}
公众时段:
/**/
//动画结束时触发,并将目标元素的位置设置为其结束值的位置
void slotOnFinish()
{
自动列表=pview.items();
静态施法(列表at(i1))
->转换位置(静态_转换(列表位于(i2));
}
};
类GraphicsView:公共QGraphicsView
{
Q_对象
公众:
GraphicsView(QGraphicscene*场景,QWidget*父对象=NULL):QGraphicsView(场景,父对象)
{
}
受保护的:
虚拟void resizeEvent(QResizeEvent*事件)Q_DECL_覆盖
{
fitInView(scene()->scene());
QGraphicsView::resizeEvent(事件);
}
};
#定义交换单元高度75
/**
*为QGraphicsView中的项目创建交换动画
*/
QParallelLanimationGroup*getSwapAnimation(QGraphicsView&view,int-noItem1,int-noItem2)
{
自动列表=view.items();
QGraphicsRectWidget*wgt1=静态_cast(list.at(noItem1));
qgraphicsretwidget*wgt2=静态_cast(list.at(noItem2));
MyAnim*pupperAnim,*plowerAnim;
QParallelLanimationGroup*par=新的QParallelLanimationGroup;
plowerAnim=新MyAnim(视图,noItem1,noItem2);
plowerAnim->setTargetObject(wgt2);
plowerAnim->setPropertyName(“pos”);
plowerAnim->setDuration(5000);
plowerAnim->setKeyValueAt(1.0/3.0,QPoint(wgt2->x(),wgt1->y()-交换高度));
plowerAnim->setKeyValueAt(2.0/3.0,QPoint(wgt1->x(),wgt1->y()-交换高度));
plowerAnim->setEndValue(wgt1->pos());
pupperAnim=新MyAnim(视图,noItem2,noItem1);
pupperAnim->setTargetObject(wgt1);
pupperAnim->setPropertyName(“pos”);
pupperAnim->setDuration(5000);
pupperAnim->setKeyValueAt(1.0/3.0,QPoint(wgt1->x(),wgt2->y()+交换高度));
pupperAnim->setKeyValueAt(2.0/3.0,QPoint(wgt2->x(),wgt2->y()+交换高度));
pupperAnim->setEndValue(wgt2->pos());
par->addAnimation(木偶动画);
par->addAnimation(plowerAnim);
返回票面金额;
}
int main(int argc,字符**argv)
{
QApplication应用程序(argc、argv);
QGraphicsRectWidget*按钮1=新的QGraphicsRectWidget;
QGraphicsRectWidget*按钮2=新的QGraphicsRectWidget;
QGraphicsRectWidget*按钮3=新的QGraphicsRectWidget;
QGraphicsRectWidget*按钮4=新的QGraphicsRectWidget;
按钮2->设置值(1);
按钮3->设置值(2);
按钮4->设置值(3);
Qgraphicscene场景(0,0,300,300);
场景:挫折地刷(QColor(23,0,0));
场景。附加项(按钮1);
场景.附加项(按钮2);
场景.附加项(按钮3);
场景.附加项(按钮4);
图形视图窗口(和场景);
window.setFrameStyle(0);
setAlignment(Qt::AlignLeft | Qt::AlignTop);
setHorizontalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
QList items=window.items();
点启动(20,125);
for(auto item:items)//在初始位置设置项
{
QGraphicsWidget*wgt=静态铸件(项目);
wgt->调整大小(50,50);
wgt->moveBy(start.x(),start.y());
start.setX(start.x()+70);
}
QSequentialAnimationGroup gr;
gr.addAnimation(getSwapAnimation(窗口,0,1));
gr.addAnimation(getSwapAnimation(窗口,1,2));
gr.addAnimation(getSwapAnimation(窗口,2,3));
gr.addAnimation(getSwapAnimation(窗口,3,1));
gr.start();
调整窗口大小(300300);
window.show();
返回app.exec();
}
#包括“main.moc”

UPD:不要为了这个目的而使用动画


UPD*:忘记上一个UPD

您的动画将保留创建动画时所涉及项目的位置。在第二个动画运行时,此信息无效

你需要重新设计动画
    #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"
// 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();
}