QPropertyAnimation for widgets in layout - problem
-
Hi all,
I wanted to make widgets increase in height with QPropertyAnimation, when widgets are arranged with QVboxLayout.
I fought that I solved this problem, but when I animate more than one widget, they start to move/shake during animation.I have prepared minimum working example, here example
The problem appears when you press "open" button for first, second, then third widget, you can see then that they are shaking, moving slightly up and down during "open" animation.Has someone idea what to do to avoid this ?
I can set setSizeConstraint(QLayout::SetFixedSize) on main layout and they dont shake, but then resizing and other doesn't work.Best Regards
Marek -
Hi
I have made it to work - with a little help ;)
so in case anyone had this problem below is single file example (main.cpp)#include <QApplication> #include <QtWidgets> class AnimLayout : public QLayout { Q_OBJECT Q_PROPERTY(QRect widgetRect READ widgetRect WRITE setWidgetRect NOTIFY widgetRectChanged) public: explicit AnimLayout(QWidget *parent = 0); ~AnimLayout(); QSize sizeHint() const; void setGeometry(const QRect &); QSize minimumSize() const; int count() const; QRect widgetRect() const; void setWidgetRect(const QRect &value); void updateItemPosition(); private: void addItem(QLayoutItem *item); QLayoutItem *itemAt(int index) const; QLayoutItem *takeAt(int index); signals: void widgetRectChanged(const QRect &value); public slots: private: QLayoutItem *item; QPropertyAnimation *animation; }; struct FrameDataStruct { QFrame *mainFrame; QFrame *upFrame; QFrame *downFrame; QPushButton *button; QVBoxLayout *upFrameLayout; QLabel *text; QVBoxLayout *downFrameLayout; QVBoxLayout *frameLayout; QPropertyAnimation *animation; int frame_id; int basic_height; bool expanded; AnimLayout *animLayout; }; class Proptest : public QMainWindow { Q_OBJECT public: explicit Proptest(); ~Proptest(); private slots: void setDataStruct(); void startAnimation(int frame_id); void animFinished(int frame_id); private: QMap<int,FrameDataStruct*> frameMap; QSignalMapper *animStartMapper; QSignalMapper *animFinishedMapper; bool initialized; QWidget *scrollWidget; QVBoxLayout *main_layout; QWidget *widget; QScrollArea *scrollArea; QVBoxLayout *central_layout; bool layoutAnimated; }; Proptest::Proptest() : widget(new QWidget) { setCentralWidget(widget); this->setGeometry(200,200,300,600); central_layout=new QVBoxLayout(widget); scrollArea=new QScrollArea(widget); central_layout->addWidget(scrollArea); animStartMapper=new QSignalMapper(this); connect(animStartMapper,SIGNAL(mapped(int)),this,SLOT(startAnimation(int))); animFinishedMapper=new QSignalMapper(this); connect(animFinishedMapper,SIGNAL(mapped(int)),this,SLOT(animFinished(int))); scrollWidget=new QWidget(widget); scrollArea->setWidget(scrollWidget); main_layout=new QVBoxLayout(scrollWidget); main_layout->setSizeConstraint(QLayout::SetMinAndMaxSize); scrollArea->setWidgetResizable(true); scrollArea->setVerticalScrollBarPolicy(Qt::ScrollBarAlwaysOn); layoutAnimated=true; this->setDataStruct(); } void Proptest::setDataStruct() { for(int i=0;i<5;i++) { FrameDataStruct *r=new FrameDataStruct; r->expanded=false; r->frame_id=i; r->mainFrame=new QFrame(scrollWidget); r->upFrame=new QFrame(r->mainFrame); r->upFrame->setMinimumHeight(40); r->button=new QPushButton(QString("open"),r->upFrame); r->upFrameLayout=new QVBoxLayout(r->upFrame); r->upFrameLayout->addWidget(r->button); r->downFrame=new QFrame(r->mainFrame); r->text=new QLabel(QString("some text SOME TEXT some text"),r->downFrame); r->downFrameLayout=new QVBoxLayout(r->downFrame); r->downFrameLayout->addWidget(r->text); r->frameLayout=new QVBoxLayout(r->mainFrame); r->frameLayout->addWidget(r->upFrame); r->frameLayout->addItem(new QSpacerItem(10,10)); r->frameLayout->addWidget(r->downFrame); r->frameLayout->setStretch(0,0); r->frameLayout->setStretch(1,1); r->frameLayout->setStretch(2,0); r->downFrame->setVisible(false); r->animation=new QPropertyAnimation(r->mainFrame,"minimumHeight"); r->animation->setDuration(500); connect(r->button,SIGNAL(clicked(bool)),animStartMapper,SLOT(map())); animStartMapper->setMapping(r->button,r->frame_id); connect(r->animation,SIGNAL(finished()),animFinishedMapper,SLOT(map())); animFinishedMapper->setMapping(r->animation,r->frame_id); if(layoutAnimated) { r->animLayout=new AnimLayout(); r->animLayout->addWidget(r->mainFrame); main_layout->addItem(r->animLayout); } else { main_layout->addWidget(r->mainFrame); } frameMap.insert(r->frame_id,r); } main_layout->addItem(new QSpacerItem(10,10,QSizePolicy::Minimum,QSizePolicy::Expanding)); main_layout->setStretch(main_layout->count()-1,1); } void Proptest::startAnimation(int frame_id) { FrameDataStruct *r=frameMap[frame_id]; if(r->expanded) { r->expanded=false; if(layoutAnimated) { r->downFrame->hide(); } else { r->downFrame->setVisible(false); r->animation->setStartValue(r->mainFrame->geometry().height()); r->animation->setEndValue(r->basic_height); } } else { r->expanded=true; if(layoutAnimated) { r->downFrame->show(); } else { r->basic_height=r->mainFrame->geometry().height(); r->animation->setStartValue(r->basic_height); r->animation->setEndValue(r->basic_height*2); r->upFrame->setMinimumHeight(r->upFrame->height()); } } if(!layoutAnimated) r->animation->start(); } void Proptest::animFinished(int frame_id) { FrameDataStruct *r=frameMap[frame_id]; if(r->expanded) r->downFrame->setVisible(true); } Proptest::~Proptest() { } AnimLayout::AnimLayout(QWidget *parent) : QLayout(parent) , item(0) { animation = new QPropertyAnimation(this); animation->setPropertyName("widgetRect"); animation->setDuration(400); animation->setTargetObject(this); } AnimLayout::~AnimLayout() { delete item; } void AnimLayout::addItem(QLayoutItem *newItem) { Q_ASSERT(!item); animation->stop(); item =newItem; emit widgetRectChanged(item->geometry()); invalidate(); } QSize AnimLayout::sizeHint() const { if (!item) return QSize(); QSize result(item->sizeHint()); int m = 2*margin(); result += QSize(m,m); return result; } void AnimLayout::updateItemPosition() { QRect dest = contentsRect(); animation->setEndValue(dest); if (widgetRect()!=dest) { animation->start(); } } void AnimLayout::setGeometry(const QRect &rect) { QLayout::setGeometry(rect); updateItemPosition(); } QLayoutItem *AnimLayout::itemAt(int i) const { return i==0?item:0; } QLayoutItem *AnimLayout::takeAt(int i) { Q_ASSERT(i==0); QLayoutItem *r = item; item = 0; return r; } QRect AnimLayout::widgetRect() const { if (item) return item->geometry(); return QRect(); } void AnimLayout::setWidgetRect(const QRect &value) { if (item && item->geometry()!=value) { item->setGeometry(value); emit widgetRectChanged(item->geometry()); } } QSize AnimLayout::minimumSize() const { QSize result(item->minimumSize()); int m = 2*margin(); result += QSize(m,m); return result; } int AnimLayout::count() const { return item?1:0; } int main(int argc, char *argv[]) { QApplication a(argc, argv); Proptest w; w.show(); return a.exec(); } #include "main.moc"
Best Regards
Marek