This post is closely related to this question about animating a QVBoxLayout, which got me half-way back when I found it.
I have a QVBoxLayout containing a few widgets. The last of them is only visible in certain situations, so I want to animate it when it appears and disappears.
I'm currently using QPropertyAnimation
to animate the maximumHeight
property of the widget I want to show and hide. However, the issue here is that I don't know what size the widget should be: the QVBoxLayout
decides that, based on the parent window size and stretch factors.
Therefore, I don't know what values I should give to QPropertyAnimation::setStartValue
and setEndValue
, for the show animation (when hiding, it should work to simply use the current height).
It sort-of works to simply give a very excessive value (such as 2000 px, when you expect it to rarely be larger than 400), since we're animating the maximum height, but that has issues. Namely, the finished
signal is emitted after the full animation duration, even if the animation stopped (visually) long ago, as the widget reached its allotted size.
When hiding, the issue is instead that the animation is delayed: from 2000 px to the current height()
, nothing happens; after that, it collapses quickly.
I then considered animating the stretch factors instead, but couldn't find a way to, since they're not exposed as properties.
As a last resort, it might be possible to subclass the layout and create a property that adjusts the stretch factor of the last two items, but that feels like a huge hack in several ways.
How can I animate this in a nice way?
Just in case somebody's going to ask for a code example, I wrote a simple test application. If you weren't going to ask, you can probably skip looking through it.
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QPropertyAnimation>
QTextEdit *topTextEdit = nullptr;
QTextEdit *bottomTextEdit = nullptr;
void toggleButtonClicked() {
QPropertyAnimation *anim = new QPropertyAnimation(bottomTextEdit,
"maximumHeight");
anim->setDuration(1200);
if (bottomTextEdit->isVisible()) {
anim->setStartValue(1000);
anim->setEndValue(0);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
bottomTextEdit->hide();
topTextEdit->append("Animation finished");
});
}
else {
bottomTextEdit->show();
anim->setStartValue(0);
anim->setEndValue(1000);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
topTextEdit->append("Animation finished");
});
}
anim->start(QAbstractAnimation::DeleteWhenStopped);
topTextEdit->append("Animation started");
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
topTextEdit = new QTextEdit;
bottomTextEdit = new QTextEdit;
QPushButton *toggleButton = new QPushButton("Toggle");
QObject::connect(toggleButton, &QPushButton::released,
&toggleButtonClicked);
QVBoxLayout *vbox = new QVBoxLayout;
vbox->addWidget(toggleButton);
vbox->addWidget(topTextEdit, 10);
vbox->addWidget(bottomTextEdit, 6);
QWidget *widget = new QWidget;
widget->setLayout(vbox);
bottomTextEdit->setMaximumHeight(0);
bottomTextEdit->hide();
widget->show();
return a.exec();
}