qt多界面来回切换卡顿问题

小王子🤴 2020-08-23 21:37:47 12811
qt多界面来回切换卡顿问题

Qt 中我们经常会用到好几个界面,那么这几个界面之间来回切换就是一个很常规的需求。但是界面切换时处理不好会出现卡顿现象 之前我也总是被这个问题困扰,现在写一个样处理凡事当作一种解决方案,希望能给大家启发。界面切换时加入动画效果,因此就研究了一下界面切换时的动画实现。本片文章介绍的动画效果是新界面飞入效果,需要其他效果可也在此基础上自行拓展

实现原理

首先来讲一下动画切换界面的实现原理,其实就是将当前界面和目标界面保存下来,然后根据动画要求将两个界面结合起来绘制到屏幕上。比如本片文章介绍的界面飞出的动画:将当前界面隐藏,把要显示的界面图片绘制到屏幕上,不是一下画完,而是根据动画时间慢慢的从头往上画。

代码实现:接下来是代码实现,步骤描述都写在注释中

#ifndef QANIMATIONSTACKEDWIDGET_H
#define QANIMATIONSTACKEDWIDGET_H

#include <QStackedWidget>
#include <QPropertyAnimation>

//枚举值,Widget切换的方向
typedef enum {
    LeftToRight,
    RightToLeft
}Direction;

/**
 * 带切换动画的stackWidget
 * 原理:如果要切换QStackedWidget当前的widget可以调用QStackedWidget::setCurrentIndex();
 * 所以在点击切换的时候播放一个动画,然后将第一个Widget和下一个Widget的过度过程绘制出来,屏蔽掉父类的QWidget函数
 * 当动画完成可以调用QStackedWidget::setCurrentIndex()函数实现界面的真正切换
 */
class QAnimationStackedWidget : public QStackedWidget
{
    Q_OBJECT
public:
    explicit QAnimationStackedWidget(QWidget *parent = nullptr);

    void paintEvent(QPaintEvent *);
    //设置动画持续的间隔
    void setDuration(int );

    ~QAnimationStackedWidget();

signals:

public slots:
    //属性动画值改变的槽
    void valueChanged_slot(QVariant );
    //动画切换完成
    void animationFinished();
    //前一页
    void next();
    //下一页
    void forward();

private:
    //绘制上一个界面
    void paintPrevious(QPainter &, int);
    //绘制下一个界面
    void paintNext(QPainter &, int);

private:
    QPropertyAnimation *animation; //动画框架
    int duration;                   //动画的持续时间
    bool isAnimation;               //是否正在动画
    QVariant       currentValue;    //被Animation动画改变的值
    int         widgetCount;        //保存当前StackWidget里面的子成员数
    int         nextIndex;          //下一个要切换的索引
    Direction   direction;          //方向
};

#endif // QANIMATIONSTACKEDWIDGET_H
#include "qanimationstackedwidget.h"
#include <QPaintEvent>
#include <QPainter>
#include <QDebug>
#include <QPixmap>

QAnimationStackedWidget::QAnimationStackedWidget(QWidget *parent) :
    QStackedWidget(parent)
{
    isAnimation = false;
    //设置默认的时间间隔
    duration = 1000;
    //初始化animation框架、并连接信号和槽
    animation = new QPropertyAnimation(this, QByteArray());
    connect(animation, SIGNAL(valueChanged(QVariant)), this, SLOT(valueChanged_slot(QVariant)));
    connect(animation, SIGNAL(finished()), this, SLOT(animationFinished()));
}

/**
 * 设置动画的持续时间
 */
void QAnimationStackedWidget::setDuration(int d)
{
    duration = d;
}

/**
 * 效果的过渡绘制实现过程
 * @param e
 */
void QAnimationStackedWidget::paintEvent(QPaintEvent *e)
{
    Q_UNUSED(e);
    if( isAnimation )
    {
        QPainter paint(this);
        switch( direction )
        {
        case LeftToRight:
            //绘制当前Widget
            paintPrevious(paint, currentIndex());
            //绘制下一个widget
            paintNext(paint, nextIndex);
            break;
        case RightToLeft:
            //绘制当前Widget
            paintPrevious(paint, nextIndex);
            //绘制下一个widget
            paintNext(paint, currentIndex());
            break;
        }

    }
}

/**
 * 绘制当前要消失的Widget
 * @param paint 画笔
 * @param currentIndex 下一个Widget的索引
 */
void QAnimationStackedWidget::paintPrevious(QPainter &paint, int currentIndex)
{
    //获得当前页面的Widget
    QWidget *w = widget(currentIndex);
    QPixmap pixmap(w->size());
    //将Widget的内容渲染到QPixmap对象中,即将Widget变成一张图片
    w->render(&pixmap);
    QRect r = w->geometry();
    //绘制当前的Widget
    double value = currentValue.toDouble();
//    QRectF r1(0.0, 0.0, value, r.height());
//    QRectF r2(r.width() - value, 0, value, r.height());
    QRectF r1(0.0, 0.0, r.width(), value);
    QRectF r2(r.width(), 0, r.width(), value);
    paint.drawPixmap(r1, pixmap, r2);
}

/**
 * 绘制下一个要显示Widget
 * @param paint     画笔
 * @param nextIndex 下一个要绘制的页面
 */
void QAnimationStackedWidget::paintNext(QPainter &paint, int nextIndex)
{
    QWidget *nextWidget = widget(nextIndex);
    QRect r = geometry();
    //这行代码不加会有bug,第一次切换的时候,QStackedWidget并没有为child分配大小
    nextWidget->resize(r.width(), r.height());
    QPixmap nextPixmap(nextWidget->size());
    nextWidget->render(&nextPixmap);
    double value = currentValue.toDouble();
//    QRectF r1(value, 0.0, r.width() - value, r.height());
//    QRectF r2(0.0, 0.0, r.width() - value, r.height());

    QRectF r1(0.0, value, r.width(), r.height() - value);
    QRectF r2(0.0, 0.0, r.width(), r.height() -value );

    paint.drawPixmap(r1, nextPixmap, r2);
}

/**
 * QPropertyAnimation的valueChanged的信号
 * @param value 动画的过程中产生的值
 */
void QAnimationStackedWidget::valueChanged_slot(QVariant value)
{
    currentValue = value;
    update();
}

/**
 * 动画完成的槽函数
 */
void QAnimationStackedWidget::animationFinished()
{
    isAnimation = false;
    widget(currentIndex())->show();
    setCurrentIndex(nextIndex);

}

/*
 * 切换到下一页
 */
void QAnimationStackedWidget::next()
{
    if( isAnimation )
    {
        return;
    }
    isAnimation = true;
    widgetCount = count();
    int c = currentIndex();
    nextIndex = (c + 1) % widgetCount;
    direction = LeftToRight;
    //隐藏当前的widget
    widget(c)->hide();
    //开始动画并设置间隔和开始、结束值
    QRect g = geometry();
//    int x = g.x();
//    int width = g.width();
//    animation->setStartValue(width);
    int height = g.height();
    animation->setStartValue(height);
    animation->setEndValue(0);
    animation->setDuration(duration);
    animation->start();
}

/*
 * 切换到上一页
 */
void QAnimationStackedWidget::forward()
{

    if( isAnimation )
    {
        return;
    }
    isAnimation = true;
    int c = currentIndex();
    widgetCount = count();
    nextIndex = (c + widgetCount - 1) % widgetCount;
    direction = RightToLeft;
    //隐藏当前的widget
    widget(c)->hide();
    //开始动画并设置间隔和开始、结束值
    QRect g = geometry();
//    int x = g.x();
//    int width = g.width();
//    animation->setStartValue(0);
//    animation->setEndValue(width);
    int height = g.height();
    animation->setStartValue(0);
    animation->setEndValue(height);
    animation->setDuration(duration);
    animation->start();
}

QAnimationStackedWidget::~QAnimationStackedWidget()
{
    if( animation )
    {
        delete animation;
        animation = NULL;
    }
}
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包 点赞 收藏 评论 打赏
评论
0个
内容存在敏感词
手气红包
    易百纳技术社区暂无数据
相关专栏
置顶时间设置
结束时间
删除原因
  • 广告/SPAM
  • 恶意灌水
  • 违规内容
  • 文不对题
  • 重复发帖
打赏作者
易百纳技术社区
小王子🤴
您的支持将鼓励我继续创作!
打赏金额:
¥1易百纳技术社区
¥5易百纳技术社区
¥10易百纳技术社区
¥50易百纳技术社区
¥100易百纳技术社区
支付方式:
微信支付
支付宝支付
易百纳技术社区微信支付
易百纳技术社区
打赏成功!

感谢您的打赏,如若您也想被打赏,可前往 发表专栏 哦~

举报反馈

举报类型

  • 内容涉黄/赌/毒
  • 内容侵权/抄袭
  • 政治相关
  • 涉嫌广告
  • 侮辱谩骂
  • 其他

详细说明

审核成功

发布时间设置
发布时间:
是否关联周任务-专栏模块

审核失败

失败原因
备注
拼手气红包 红包规则
祝福语
恭喜发财,大吉大利!
红包金额
红包最小金额不能低于5元
红包数量
红包数量范围10~50个
余额支付
当前余额:
可前往问答、专栏板块获取收益 去获取
取 消 确 定

小包子的红包

恭喜发财,大吉大利

已领取20/40,共1.6元 红包规则

    易百纳技术社区