qt QPainter QPropertyAnimation 实现翻转

来源:互联网 发布:好看的手写字体知乎 编辑:程序博客网 时间:2024/06/03 11:18

前段时间用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();
}
以下为效果图 ,支持自适应罗

项目到此下载