翻转动画

效果如下:

实现思路:

1、放了1个stacked widget

2、里面放了2个widget,一个蓝色一个红色

3、鼠标点击时,将2个widget隐藏,开启动画

4、通过动画不停的修改旋转角度,然后重绘界面

5、重绘时:将两个widget的内容渲染到2个QPixmap中,然后将这2个pixmap绕y轴旋转绘制上去

小于90度时绘制第一个pixmap,大于90时绘制第二个pixmap

6、动画结束后,设置stacked widget的当前widget

#ifndef WIDGET_H
#define WIDGET_H

#include <QWidget>
#include<QStackedWidget>
#include<QHBoxLayout>
#include<QPainter>
#include<QTransform>
#include<QPropertyAnimation>
#include<QPushButton>


class Widget : public QWidget
{
    Q_OBJECT

    Q_PROPERTY(int rotation READ getRotation WRITE setRotation NOTIFY rotationChanged FINAL)

public:
    Widget(QWidget *parent = nullptr) : QWidget(parent)
    {
        resize(800,600);

        QHBoxLayout* h_box=new QHBoxLayout(this);
        //放了一个stacked widget
        sw=new QStackedWidget(this);
        h_box->addWidget(sw);

        //往里面放两个Widget 一个红色一个蓝色,点击后实现翻转效果切换
        w1=new QWidget(this);
        w1->setStyleSheet("background-color:red");
        QPushButton* btn=new QPushButton("我是w1",w1);
        btn->setGeometry(20,20,100,30);
        sw->addWidget(w1);

        w2=new QWidget(this);
        w2->setStyleSheet("background-color:blue");
        QPushButton* btn2=new QPushButton("我是w2",w2);
        btn2->setGeometry(20,20,100,30);
        sw->addWidget(w2);

        sw->setCurrentIndex(0);


        //使用QPropertyAnimation来实现动画,不停的修改旋转角度rotation
        animation=new QPropertyAnimation(this,"rotation",this);
        animation->setStartValue(0);
        animation->setEndValue(180);
        animation->setDuration(2000);//设置动画时长2s

        //动画结束后将对应stacked widget要显示的widget更新并显示
        connect(animation,&QPropertyAnimation::finished,this,[=](){
            //更新stacked widget里面当前的widget
            int index=sw->currentIndex();
            if(index==sw->count()-1)
            {
                index=0;
            }
            else{
                ++index;
            }
            sw->setCurrentIndex(index);
        });
    }
    ~Widget()=default;


    int getRotation() const
    {
        return rotation;
    }

    //旋转角度每次更新时都update重绘
    void setRotation(int newRotation)
    {
        if (rotation == newRotation)
            return;
        rotation = newRotation;
        emit rotationChanged();
        update();
    }

signals:
    void rotationChanged();

protected:
    //主要思路,将w1和w2先隐藏,
    //然后旋转角度小于90度时将w1的内容渲染到一个QPixmap上,旋转角度大于90度时将w2的内容渲染到QPixmap上
    void paintEvent(QPaintEvent* ev) override
    {
        //只有动画开启后才执行这一段的绘制
        if(animation->state()==QPropertyAnimation::Running)
        {
            QPainter painter(this);
            painter.setRenderHint(QPainter::SmoothPixmapTransform);
            QPixmap pix(sw->size());


            //使用变换类QTransform搭配QPainter
            QTransform trans;
            trans.translate(rect().center().x(),rect().center().y());//移动到中心

            //小于90度
            if(rotation<90)
            {
                //将stacked widget中当前widget渲染到图片上
                sw->currentWidget()->render(&pix);

                trans.rotate(rotation,Qt::YAxis);//QTransform的旋转可以设置绕某个轴旋转,这里绕y轴旋转

            }
            else//大于90度
            {
                //将下一个widget渲染到图片上
                int index=sw->currentIndex();
                if(index==sw->count()-1)
                {
                    index=0;
                }
                else{
                    ++index;
                }
                sw->widget(index)->render(&pix);

                //解决镜像问题180-rotation
                trans.rotate(rotation-180,Qt::YAxis);
            }



            painter.setTransform(trans);
            //将被渲染了w1或w2内容的QPixmap绘制上去
            painter.drawPixmap(QPoint(-sw->width()/2,-sw->height()/2),pix);
        }

        QWidget::paintEvent(ev);

    }

    //鼠标点击时开启动画效果
    void mousePressEvent(QMouseEvent* ev)
    {
        //动画还在执行中,那么等他执行完
        if(animation->state()==QPropertyAnimation::Running)
        {
            return;
        }

        //先将stacked widget中的2个widget隐藏
        for(int i=0;i<sw->count();++i)
        {
            //解决第一次翻转时,其中有些widget的尺寸和stacked widget不一致导致渲染搭配pixmap上的内容太小
            sw->widget(i)->resize(sw->size());


            sw->widget(i)->hide();
        }


        animation->start();

    }

private:
    QStackedWidget* sw;
    QWidget* w1;
    QWidget* w2;

    int rotation=0;
    QPropertyAnimation* animation;

};
#endif // WIDGET_H

知识点:

  • 可以将widget中的内容渲染到一张图片中QPixmap

QWidget::render方法

QPixmap pixmap(widget->size());
widget->render(&pixmap);
  • 利用QTransform给QPainter设置变换

其中rotate方法可以设置使得QPainter绕某个轴(x,y,z)旋转

默认是z轴,也就是在xy平面中旋转

QTransform &QTransform::rotate(qreal a, Qt::Axis axis = Qt::ZAxis)
QTransform trans;
trans.translate(rect().center().x(),rect().center().y());//移动到中心
trans.rotate(rotation,Qt::YAxis);//QTransform的旋转可以设置绕某个轴旋转,这里绕y轴旋转
painter.setTransform(trans);

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值