Qt 使用拉伸因子/最终尺寸未知时设置QVBoxLayout动画
这篇文章和我的关系密切,当我找到它的时候,它让我回到了一半 我有一个QVBoxLayout,其中包含一些小部件。最后一个仅在某些情况下可见,因此我希望在它出现和消失时对其进行动画处理。Qt 使用拉伸因子/最终尺寸未知时设置QVBoxLayout动画,qt,animation,Qt,Animation,这篇文章和我的关系密切,当我找到它的时候,它让我回到了一半 我有一个QVBoxLayout,其中包含一些小部件。最后一个仅在某些情况下可见,因此我希望在它出现和消失时对其进行动画处理。 我目前正在使用QPropertyAnimation设置要显示和隐藏的小部件的maximumHeight属性的动画。然而,这里的问题是,我不知道小部件应该是什么大小:QVBoxLayout根据父窗口大小和拉伸系数决定。 因此,对于show动画,我不知道应该为QPropertyAnimation::setStartV
我目前正在使用
QPropertyAnimation
设置要显示和隐藏的小部件的maximumHeight
属性的动画。然而,这里的问题是,我不知道小部件应该是什么大小:QVBoxLayout根据父窗口大小和拉伸系数决定。
因此,对于show动画,我不知道应该为QPropertyAnimation::setStartValue
和setEndValue
赋予哪些值(隐藏时,只需使用当前高度即可)
简单地给出一个非常大的值(比如2000px,当你期望它很少大于400时)是可行的,因为我们正在设置最大高度的动画,但这有问题。也就是说,当小部件达到其分配的大小时,即使动画在很久以前(视觉上)停止,在整个动画持续时间后仍会发出finished
信号。隐藏时,问题是动画被延迟:从2000像素到当前的
高度()
,什么都没有发生;在那之后,它很快就崩溃了
然后我考虑设置拉伸因子的动画,但找不到一种方法,因为它们没有作为属性公开。作为最后一种手段,可能会对布局进行子类化,并创建一个属性来调整最后两个项目的拉伸因子,但从几个方面来看,这感觉像是一个巨大的难题 如何以一种好的方式设置动画 为了防止有人问起代码示例,我编写了一个简单的测试应用程序。如果你不想问的话,你可以不看了
#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();
}
#包括
#包括
#包括
#包括
#包括
QTextEdit*topTextEdit=nullptr;
QTextEdit*bottomTextEdit=nullptr;
void toggleButtonClicked(){
QPropertyAnimation*anim=新的QPropertyAnimation(底部文本编辑,
“最大高度”);
动画->设定持续时间(1200);
如果(bottomTextEdit->isVisible()){
动画->设置起始值(1000);
动画->设置结束值(0);
QObject::connect(动画,&QPropertyAnimation::已完成,[]{
底部文本编辑->隐藏();
topTextEdit->append(“动画完成”);
});
}
否则{
底部文本编辑->显示();
动画->设置开始值(0);
动画->设定值(1000);
QObject::connect(动画,&QPropertyAnimation::已完成,[]{
topTextEdit->append(“动画完成”);
});
}
动画->开始(QAbstractAnimation::DeleteWhenStopped);
topTextEdit->append(“动画开始”);
}
int main(int argc,char*argv[])
{
质量保证申请a(argc、argv);
topTextEdit=新的QTextEdit;
bottomTextEdit=新的QTextEdit;
QPushButton*toggleButton=新的QPushButton(“切换”);
QObject::connect(切换按钮和QPushButton::已发布),
&切换按钮(已单击);
QVBoxLayout*vbox=新的QVBoxLayout;
vbox->addWidget(切换按钮);
vbox->addWidget(topTextEdit,10);
vbox->addWidget(底部文本编辑,6);
QWidget*widget=新的QWidget;
小部件->设置布局(vbox);
底部文本编辑->设置最大高度(0);
底部文本编辑->隐藏();
widget->show();
返回a.exec();
}
我最终选择了子类化路线,因为我想不出其他任何东西,而且这个问题没有看到太多的活动
子类(必须在头文件中,否则将获得对vtable错误的未定义引用):
实现后,将QVBoxLayout
替换为EVBoxLayout
,并使用
QPropertyAnimation *anim = new QPropertyAnimation(vbox, "lastStretch");
<> P>有几个要点需要考虑:
- 为了使动画平滑,您可能应该使用非常大的拉伸因子;因为它们是整数,所以从1到5的动画将非常不稳定。我使用了1000:600的比例,所以底部小部件的动画是从1到600,我希望是较小的李>
- 确保将小部件的最小高度设置为1(而不是0!),否则动画可能会以部分方式开始
- 确保从1而不是从0设置拉伸因子的动画,否则动画开始时会闪烁
为完整起见,以下是完整的测试程序,已更新以使用此修复程序: 主要条款h:
#ifndef MAIN_H
#define MAIN_H
#include <QVBoxLayout>
class EVBoxLayout : public QVBoxLayout {
Q_OBJECT
Q_PROPERTY(int lastStretch READ lastStretch WRITE setLastStretch)
public:
int lastStretch() const { return this->stretch(this->count() - 1); }
void setLastStretch(int newStretch) { this->setStretch(this->count() - 1, newStretch); }
};
#endif // MAIN_H
#如果主
#定义主
#包括
EVBoxLayout类:公共QVBoxLayout{
Q_对象
Q_属性(int lastStretch读取lastStretch写入setLastStretch)
公众:
int lastStretch()常量{返回此->拉伸(此->计数()-1);}
void setLastStretch(int newStretch){this->setStretch(this->count()-1,newStretch);}
};
#endif//MAIN_H
main.cpp:
#include "main.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QPropertyAnimation>
QTextEdit *topTextEdit = nullptr;
QTextEdit *bottomTextEdit = nullptr;
EVBoxLayout *vbox = nullptr;
void toggleButtonClicked() {
QPropertyAnimation *anim = new QPropertyAnimation(vbox, "lastStretch");
anim->setDuration(250);
// Without this, the scrollbar may appear (and then disappear again)
// during animation.
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
if (bottomTextEdit->isVisible()) {
anim->setStartValue(600);
anim->setEndValue(1);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
bottomTextEdit->hide();
topTextEdit->append("Animation finished");
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
});
}
else {
bottomTextEdit->show();
anim->setStartValue(1);
anim->setEndValue(600);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
topTextEdit->append("Animation finished");
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
});
}
anim->start(QAbstractAnimation::DeleteWhenStopped);
topTextEdit->append("Animation started");
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
topTextEdit = new QTextEdit;
bottomTextEdit = new QTextEdit;
bottomTextEdit->setMinimumHeight(1);
QPushButton *toggleButton = new QPushButton("Toggle");
QObject::connect(toggleButton, &QPushButton::released,
&toggleButtonClicked);
vbox = new EVBoxLayout;
vbox->addWidget(toggleButton);
vbox->addWidget(topTextEdit, 1000);
vbox->addWidget(bottomTextEdit, 1);
QWidget *widget = new QWidget;
widget->setLayout(vbox);
bottomTextEdit->hide();
widget->show();
return a.exec();
}
#包括“main.h”
#包括
#包括
#包括
#包括
#包括
QTextEdit*topTextEdit=nullptr;
QTextEdit*bottomTextEdit=nullptr;
EVBoxLayout*vbox=nullptr;
void toggleButtonClicked(){
QPropertyAnimation*anim=新的QPropertyAnimation(vbox,“lastStretch”);
动画->设定持续时间(250);
//否则,滚动条可能会出现(然后再次消失)
//在动画中。
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
如果(bottomTextEdit->isVisible()){
动画->设置起始值(600);
动画->设置结束值(1);
QObject::connect(动画,&QPropertyAnimation::已完成,[]{
底部文本编辑->隐藏();
topTextEdit->append(“动画完成”);
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsneed);
});
}
否则{
底部文本编辑->显示();
动画->设置开始值(1);
一
#include "main.h"
#include <QApplication>
#include <QVBoxLayout>
#include <QPushButton>
#include <QTextEdit>
#include <QPropertyAnimation>
QTextEdit *topTextEdit = nullptr;
QTextEdit *bottomTextEdit = nullptr;
EVBoxLayout *vbox = nullptr;
void toggleButtonClicked() {
QPropertyAnimation *anim = new QPropertyAnimation(vbox, "lastStretch");
anim->setDuration(250);
// Without this, the scrollbar may appear (and then disappear again)
// during animation.
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOff);
if (bottomTextEdit->isVisible()) {
anim->setStartValue(600);
anim->setEndValue(1);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
bottomTextEdit->hide();
topTextEdit->append("Animation finished");
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
});
}
else {
bottomTextEdit->show();
anim->setStartValue(1);
anim->setEndValue(600);
QObject::connect(anim, &QPropertyAnimation::finished, [] {
topTextEdit->append("Animation finished");
bottomTextEdit->setVerticalScrollBarPolicy(Qt::ScrollBarAsNeeded);
});
}
anim->start(QAbstractAnimation::DeleteWhenStopped);
topTextEdit->append("Animation started");
}
int main(int argc, char *argv[])
{
QApplication a(argc, argv);
topTextEdit = new QTextEdit;
bottomTextEdit = new QTextEdit;
bottomTextEdit->setMinimumHeight(1);
QPushButton *toggleButton = new QPushButton("Toggle");
QObject::connect(toggleButton, &QPushButton::released,
&toggleButtonClicked);
vbox = new EVBoxLayout;
vbox->addWidget(toggleButton);
vbox->addWidget(topTextEdit, 1000);
vbox->addWidget(bottomTextEdit, 1);
QWidget *widget = new QWidget;
widget->setLayout(vbox);
bottomTextEdit->hide();
widget->show();
return a.exec();
}