运行 QPropertyAnimation 后 QWiget 的奇怪行为
Posted
技术标签:
【中文标题】运行 QPropertyAnimation 后 QWiget 的奇怪行为【英文标题】:Weird behaviour of QWiget after running QPropertyAnimation 【发布时间】: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::arrayleft, 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】:问题在于您将小部件放置在布局中,然后尝试自己管理它们的几何形状。一种解决方法是在动画组完成后通过交换两个小部件来更新布局。然后你的代码就变成了……
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::arrayleft, 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);
);
请注意,如果在动画期间 调整父小部件的大小,您可能仍会看到一些奇怪的行为。
【讨论】:
是的,这帮助我得到了一个几乎相同的最终解决方案 + 在动画开始时禁用窗口调整大小,并在动画结束时启用调整大小。以上是关于运行 QPropertyAnimation 后 QWiget 的奇怪行为的主要内容,如果未能解决你的问题,请参考以下文章
PyQt5 QPropertyAnimation finished() 如何连接
Qt 4.6.2 - QPropertyAnimation 不起作用
QPainter 在使用 QPropertyAnimation 时崩溃