Qt QPropertyAnimation布局中的小部件 - 小部件抖动

时间:2016-09-14 08:55:56

标签: c++ qt animation

当使用QVboxLayout排列小部件时,我希望使用QPropertyAnimation使小部件的高度增加。 问题是,当我打开多个小部件时,它们会在动画期间开始移动/摇动。

我准备了最低工作示例,tar gz project 按"打开"第一个,第二个,然后第三个小部件的按钮,你可以看到他们正在摇晃,在"打开"动画。

有人知道该怎么做才能避免这种情况吗? 我可以在主布局上设置setSizeConstraint(QLayout :: SetFixedSize)并且它们不会动摇,但是然后调整大小并且其他不起作用。

最好的问候

马立克

3 个答案:

答案 0 :(得分:0)

前段时间我写了一个布局,它动画了它包含的小部件位置。 您应该以这样的方式构建您的布局:每个应该被动画化的小部件都应该在这个布局中(每个小部件一个Memory Leaks应该是动画的):

public void renameItems(Activity activity, ...) {

AlertDialog.Builder builderInner = new AlertDialog.Builder(activity, R.style.MyAlertDialogStyle);

    LinearLayout layout = new LinearLayout(activity);
    final TextView itemTitle = new TextView(activity);
    final EditText itemTitleInput = new EditText(activity);
    final TextView subItem = new TextView(activity);
    final EditText subItemInput = new EditText(activity);

// Irrelevant code ...

} 

它有一些你不需要的额外功能(AnimLayout)。

答案 1 :(得分:0)

对不起它花了我这么久;) 我测试了它,效果很好。

然而,当我使用我之前的代码时,我已经让它工作而不会摇晃。我做的更改是将QWidget添加到QScrollArea中,然后在该小部件上设置QVBoxLayout。 无论如何,非常感谢你的帮助。 下面是一个main.cpp中的示例,并且有变量" animatedLayout"打开或关闭AnimLayout。


    #include 
    #include 

    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 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;iexpanded=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"

最好的问候

马立克

答案 2 :(得分:0)

我的回答再次,不知道为什么,但删除了previosu。

我使用了你的AnimLayout,效果很好。 下面是main.cpp中的示例,其中包含" layoutAnimated"变量来打开和关闭AnimLayout。

#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"

最好的问候

马立克