Странное поведение QWiget после запуска QPropertyAnimation - PullRequest
0 голосов
/ 25 января 2019

Я запускаю следующую анимацию на двух виджетах:

QParallelAnimationGroup* animGroup = new QParallelAnimationGroup;

for (int i = 0; i < 2; ++i) {
    //widgets is an array of 2 QLabels
    QPropertyAnimation* anim = new QPropertyAnimation(widgets[i], "geometry");
    anim->setDuration(750);
    anim->setStartValue(widgets[i]->geometry());
    widgets[i]->setProperty("animating", true);
    qDebug() << QString("Animation Start %1: ").arg(widgets[i]->objectName()) << widgets[i]->pos() << " g " << widgets[i]->geometry();
    //
    anim->setEndValue(widgets[!i]->geometry());
    anim->setEasingCurve(QEasingCurve::OutBack);
    animGroup->addAnimation(anim);
}

animGroup->start(QAbstractAnimation::DeleteWhenStopped);

Пока все хорошо, анимация перемещает оба виджета, как и ожидалось, но как только я изменяю размер окна, эти виджеты автоматически перемещаются назад.в исходное положение.Текущий макет, содержащий оба этих виджета, является QHBoxLayout и имеет следующие элементы (в том же порядке):

QLabel0 |QSpacerItem0 |QToolTipButton |QSpacerItem1 | QLabel1

после анимации они становятся:

QLabel1 |QSpacerItem0 |QToolTipButton |QSpacerItem1 | QLabel0

Но всякий раз, когда я изменяю размер окна, положение виджетов сбрасывается в исходное расположение.Я не реализовал resizeEvent из своего окна.

Я использую Windows 10 с Visual Studio |Qt Visual Studio Tools 2.3.1 и Qt 12.0, сборка с версией msvc2017_64 и включенным c ++ 17.

Полный тестовый код (новый проект):

SwapItemsTest.cpp

#include "SwapItemsTest.h"

#include <array>

#include <QHBoxLayout>
#include <QToolButton>
#include <QSpacerItem>
#include <QLabel>
#include <QDebug>
#include <QParallelAnimationGroup>
#include <QPropertyAnimation>
#include <QTimer>

SwapItemsTest::SwapItemsTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    auto layout = new QHBoxLayout;

    auto toolButton = new QToolButton;

    auto left = new QLabel("Left");
    left->setFixedSize(50, size().height());
    left->setFrameShape(QFrame::Box);
    left->setFrameShadow(QFrame::Plain);
    left->setLineWidth(2);

    left->setAlignment(Qt::AlignCenter);

    auto right = new QLabel("Right");

    right->setFixedSize(50, size().height());
    right->setAlignment(Qt::AlignCenter);
    right->setFrameShape(QFrame::Box);
    right->setFrameShadow(QFrame::Plain);
    right->setLineWidth(2);

    layout->addWidget(left);

    layout->addSpacerItem(new QSpacerItem(40, 40));

    layout->addWidget(toolButton);

    layout->addSpacerItem(new QSpacerItem(40, 40));

    layout->addWidget(right);

    ui.centralWidget->setLayout(layout);

    auto widgets = std::array{left, right};

    connect(toolButton, &QToolButton::clicked, [widgets]() {
        QParallelAnimationGroup* animGroup = new QParallelAnimationGroup;

        for (int i = 0; i < 2; ++i) {
            //widgets is an array of 2 QLabels
            QPropertyAnimation* anim = new QPropertyAnimation(widgets[i], "geometry");
            anim->setDuration(750);
            anim->setStartValue(widgets[i]->geometry());
            widgets[i]->setProperty("animating", true);
            anim->setEndValue(widgets[!i]->geometry());
            anim->setEasingCurve(QEasingCurve::OutBack);
            animGroup->addAnimation(anim);
        }

        animGroup->start(QAbstractAnimation::DeleteWhenStopped); 
    });


}

SwapItemsTest.h

#pragma once

#include <QtWidgets/QMainWindow>
#include "ui_SwapItemsTest.h"

class SwapItemsTest : public QMainWindow
{
    Q_OBJECT

public:
    SwapItemsTest(QWidget *parent = Q_NULLPTR);

private:
    Ui::SwapItemsTestClass ui;
};

1 Ответ

0 голосов
/ 25 января 2019

Проблема в том, что вы размещаете виджеты в макете, но затем пытаетесь сами управлять их геометрией. Одним из обходных путей будет обновление макета после завершения анимационной группы путем замены двух виджетов. Ваш код становится ...

SwapItemsTest::SwapItemsTest(QWidget *parent)
    : QMainWindow(parent)
{
    ui.setupUi(this);

    auto layout = new QHBoxLayout;

    auto toolButton = new QToolButton;

    auto left = new QLabel("Left");
    left->setFixedSize(50, size().height());
    left->setFrameShape(QFrame::Box);
    left->setFrameShadow(QFrame::Plain);
    left->setLineWidth(2);

    left->setAlignment(Qt::AlignCenter);

    auto right = new QLabel("Right");

    right->setFixedSize(50, size().height());
    right->setAlignment(Qt::AlignCenter);
    right->setFrameShape(QFrame::Box);
    right->setFrameShadow(QFrame::Plain);
    right->setLineWidth(2);

    layout->addWidget(left);

    layout->addSpacerItem(new QSpacerItem(40, 40));

    layout->addWidget(toolButton);

    layout->addSpacerItem(new QSpacerItem(40, 40));

    layout->addWidget(right);

    ui.centralWidget->setLayout(layout);

    auto widgets = std::array{left, right};

    connect(toolButton, &QToolButton::clicked,

            /*
             * Note that layout has been added to the capture list for this lambda.
             */
            [layout, widgets]()
            {
                QParallelAnimationGroup* animGroup = new QParallelAnimationGroup;

                for (int i = 0; i < 2; ++i) {
                    //widgets is an array of 2 QLabels
                    QPropertyAnimation* anim = new QPropertyAnimation(widgets[i], "geometry");
                    anim->setDuration(750);
                    anim->setStartValue(widgets[i]->geometry());
                    widgets[i]->setProperty("animating", true);
                    anim->setEndValue(widgets[!i]->geometry());
                    anim->setEasingCurve(QEasingCurve::OutBack);
                    animGroup->addAnimation(anim);
                }

                /*
                 * This is the lambda that will be invoked when the
                 * QPropertyAnimation::finished signal is emitted.  It simply
                 * swaps the positions of the two widgets in the layout.
                 */
                connect(animGroup, &QPropertyAnimation::finished,
                        [layout, widgets]()
                        {
                            auto index0 = layout->indexOf(widgets[0]);
                            auto index1 = layout->indexOf(widgets[1]);
                            if (index0 < index1) {
                                layout->takeAt(index1);
                                layout->takeAt(index0);
                                layout->insertWidget(index0, widgets[1]);
                                layout->insertWidget(index1, widgets[0]);
                            } else {
                                layout->takeAt(index0);
                                layout->takeAt(index1);
                                layout->insertWidget(index1, widgets[0]);
                                layout->insertWidget(index0, widgets[1]);
                            }
                        });

                animGroup->start(QAbstractAnimation::DeleteWhenStopped);
            });
}

Обратите внимание, что вы все еще можете увидеть странное поведение, если размер родительского виджета изменяется во время анимации.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...