技术专栏
qt多界面来回切换卡顿问题
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
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
<
#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;
}
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- 41
- 42
- 43
- 44
- 45
- 46
- 47
- 48
- 49
- 50
- 51
- 52
- 53
- 54
- 55
- 56
- 57
- 58
- 59
- 60
- 61
- 62
- 63
- 64
- 65
- 66
- 67
- 68
- 69
- 70
- 71
- 72
- 73
- 74
- 75
- 76
- 77
- 78
- 79
- 80
- 81
- 82
- 83
- 84
- 85
- 86
- 87
- 88
- 89
- 90
- 91
- 92
- 93
- 94
- 95
- 96
- 97
- 98
- 99
- 100
- 101
- 102
- 103
- 104
- 105
- 106
- 107
- 108
- 109
- 110
- 111
- 112
- 113
- 114
- 115
- 116
- 117
- 118
- 119
- 120
- 121
- 122
- 123
- 124
- 125
- 126
- 127
- 128
- 129
- 130
- 131
- 132
- 133
- 134
- 135
- 136
- 137
- 138
- 139
- 140
- 141
- 142
- 143
- 144
- 145
- 146
- 147
- 148
- 149
- 150
- 151
- 152
- 153
- 154
- 155
- 156
- 157
- 158
- 159
- 160
- 161
- 162
- 163
- 164
- 165
- 166
- 167
- 168
- 169
- 170
- 171
- 172
- 173
- 174
- 175
- 176
- 177
- 178
- 179
- 180
- 181
- 182
- 183
- 184
- 185
- 186
- 187
<
声明:本文内容由易百纳平台入驻作者撰写,文章观点仅代表作者本人,不代表易百纳立场。如有内容侵权或者其他问题,请联系本站进行删除。
红包
点赞
收藏
评论
打赏
- 分享
- 举报
评论
0个
手气红包

相关专栏
-
浏览量:3551次2020-08-11 11:35:54
-
浏览量:6978次2020-11-24 23:15:35
-
浏览量:843次2023-07-26 10:00:21
-
浏览量:5740次2021-08-12 14:06:09
-
浏览量:2922次2017-10-30 16:52:18
-
浏览量:1759次2023-06-12 14:34:21
-
浏览量:899次2024-01-22 16:42:18
-
浏览量:2796次2021-12-25 09:00:17
-
浏览量:1537次2023-06-02 17:41:13
-
浏览量:4968次2021-03-26 16:03:04
-
2023-12-11 10:52:14
-
浏览量:989次2023-08-09 15:19:33
-
浏览量:3913次2020-08-18 19:54:58
-
浏览量:9582次2020-08-23 21:42:54
-
浏览量:3364次2020-08-22 16:09:02
-
浏览量:1797次2020-02-28 09:50:55
-
浏览量:1737次2018-02-17 00:18:09
-
浏览量:1333次2022-12-16 12:31:41
-
浏览量:4000次2020-07-17 16:50:14
置顶时间设置
结束时间
删除原因
-
广告/SPAM
-
恶意灌水
-
违规内容
-
文不对题
-
重复发帖
打赏作者

小王子🤴
您的支持将鼓励我继续创作!
打赏金额:
¥1

¥5

¥10

¥50

¥100

支付方式:

举报反馈
举报类型
- 内容涉黄/赌/毒
- 内容侵权/抄袭
- 政治相关
- 涉嫌广告
- 侮辱谩骂
- 其他
详细说明
审核成功
发布时间设置
发布时间:
请选择发布时间设置
是否关联周任务-专栏模块
审核失败
失败原因
请选择失败原因
备注
请输入备注