Warning: file_get_contents(/data/phpspider/zhask/data//catemap/8/qt/7.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Qt 使用拉伸因子/最终尺寸未知时设置QVBoxLayout动画_Qt_Animation - Fatal编程技术网

Qt 使用拉伸因子/最终尺寸未知时设置QVBoxLayout动画

Qt 使用拉伸因子/最终尺寸未知时设置QVBoxLayout动画,qt,animation,Qt,Animation,这篇文章和我的关系密切,当我找到它的时候,它让我回到了一半 我有一个QVBoxLayout,其中包含一些小部件。最后一个仅在某些情况下可见,因此我希望在它出现和消失时对其进行动画处理。 我目前正在使用QPropertyAnimation设置要显示和隐藏的小部件的maximumHeight属性的动画。然而,这里的问题是,我不知道小部件应该是什么大小:QVBoxLayout根据父窗口大小和拉伸系数决定。 因此,对于show动画,我不知道应该为QPropertyAnimation::setStartV

这篇文章和我的关系密切,当我找到它的时候,它让我回到了一半

我有一个QVBoxLayout,其中包含一些小部件。最后一个仅在某些情况下可见,因此我希望在它出现和消失时对其进行动画处理。
我目前正在使用
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();
}