qt QPainter QPropertyAnimation 实现翻转

前段时间用QGraphics框架实现过qq的翻转效果,当时也提到过其实这个功能还可以用QPainter来实现,原因是因为QPainter同样支持QTransform的

转换操作。另外一个知识点就是,QWidget窗体在paintEvent中可以通过QWidget::render(QPainter *,QPoint offset,QRegion sourceRegion)函数画出来,这样

如果我们再接合QPropertyAnimation不难实现翻转效果。

代码如下

#define TRANSFORMWIDGET_H

#include <QWidget>
#include <QMap>

QT_FORWARD_DECLARE_CLASS(QPropertyAnimation)
class TransformWidget : public QWidget
{
    Q_OBJECT
    Q_PROPERTY(qreal tranformY READ tranformY WRITE setTranformY NOTIFY tranformYChanged)
public:
    TransformWidget(QWidget *parent = nullptr);
    QWidget *front() const;       //前面
    QWidget *back() const;        //后面
    void setFront(QWidget *front);
    void setBack(QWidget *back);
    void start();

signals:
    void tranformYChanged();

protected:
    void paintEvent(QPaintEvent *event);
    void setTranformY(qreal angle = 0);  //旋转一定角度
    qreal tranformY() const;

private:
    qreal _angle{0};
    QPropertyAnimation *ani{nullptr};
    QMap<QString,QWidget*> _widgetMap;  //保存前后两面QWidge指针
};

#endif // TRANSFORMWIDGET_H

#include "transformwidget.h"
#include <QTransform>
#include <QPainter>
#include <QDebug>
#include <QPropertyAnimation>
#include <QPaintEvent>

TransformWidget::TransformWidget(QWidget *parent):
    QWidget(parent)
{
    ani = new QPropertyAnimation(this,"tranformY",this);
    ani->setDuration(3000);
    ani->setStartValue(0);
    ani->setEndValue(180);
    ani->setEasingCurve(QEasingCurve::InCurve);
    connect(ani,&QPropertyAnimation::finished,[&]{ani->setDirection(QPropertyAnimation::Direction(!ani->direction()));});
}

void TransformWidget::setFront(QWidget *front)
{
    if(!front)
        return;
    _widgetMap["front"] = front; //添加前窗体
}

void TransformWidget::setBack(QWidget *back)
{
    if(!back)
        return;
    _widgetMap["back"] = back; //添加后窗体
}

void TransformWidget::setTranformY(qreal angle)
{
    if(_widgetMap.count() != 2){
        qDebug() << "please ensure you has been set front and back Widget";
        return;
    }

    if(angle != _angle)
        emit tranformYChanged();

    _angle = angle;
    update();
}

qreal TransformWidget::tranformY() const
{
    return _angle;
}

void TransformWidget::paintEvent(QPaintEvent *event)
{
    QWidget *w{nullptr};
    if(_angle > 90){   //以90度为基准
        w = _widgetMap.value("back");
    }else{
        w = _widgetMap.value("front");
    }

    QPainter painter(this);
    painter.setWindow(0,0,128,128); //设置painter绘图逻辑坐标,默认与this窗口一致;使其能自适应,因为视口默认与窗口一致的
    QTransform fm;
    fm.translate(w->width() >> 1,0);
    fm.rotate(_angle,Qt::YAxis);
    fm.translate(-w->width() >> 1,0);
    painter.setTransform(fm);
    w->render(&painter);
    painter.end();
    return QWidget::paintEvent(event);
}

void TransformWidget::start()
{
    ani->start();
}

在main.cpp中我们只需要添加两个窗体,并启动动画就可以了

#include "widget.h"
#include <QApplication>
#include "transformwidget.h"
#include <QLabel>
#include <QTimer>
#include <QDebug>

int main(int argc, char *argv[])
{
    QApplication a(argc, argv);
    QLabel *label = new QLabel;
    label->setPixmap(QPixmap(":/trash.png"));

    TransformWidget w;
    w.setFront(label);

    label = new QLabel;
    label->setPixmap(QPixmap(":/test.png"));
    w.setBack(label);

    QTimer tm;
    tm.setInterval(3500);
    QObject::connect(&tm,&QTimer::timeout,[&]{w.start();});

    w.show();

    tm.start();

    return a.exec();
}


以下为效果图 ,支持自适应罗

项目到此下载




评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值