【问题标题】:Weird behaviour of QWiget after running QPropertyAnimation运行 QPropertyAnimation 后 QWiget 的奇怪行为
【发布时间】:2019-01-25 06:28:21
【问题描述】:

我正在两个小部件上运行下一个动画:

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。

我正在使用带有 Visual Studio 的 Windows 10 | 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;
};

【问题讨论】:

    标签: c++ visual-studio qt


    【解决方案1】:

    问题在于您将小部件放置在布局中,然后尝试自己管理它们的几何形状。一种解决方法是在动画组完成后通过交换两个小部件来更新布局。然后你的代码就变成了……

    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);
                });
    }
    

    请注意,如果在动画期间 调整父小部件的大小,您可能仍会看到一些奇怪的行为。

    【讨论】:

    • 是的,这帮助我得到了一个几乎相同的最终解决方案 + 在动画开始时禁用窗口调整大小,并在动画结束时启用调整大小。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2011-10-07
    • 1970-01-01
    • 2012-02-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多