带切换动画的QStackedWidget
来源:互联网 发布:肉肉耽美网络剧百度云 编辑:程序博客网 时间:2024/06/11 02:40
前言
有些时候我们使用QStackedWidget想要切换动画,就比如酷狗的这种效果:
使用自带的QStackedWidget是无法达到动画的切换效果的,所以为了满足这种需求我们可以继承QStackedWidget并结合使用QPropertyAnimation就可以达到这种效果。
原理
我们知道,要切换QStackedWidget当前的显示界面可以调用QStackedWidget::setCurrentIndex()函数来切换,这种切换是跳跃式的,所以我们的动画就是在调用这个setCurrentIndex()函数之前开始,动画结束之后再调用setCurrentIndex()函数,这样就可以看到动画了。
但是这中间的动画过程要做什么事呢?那当然就是将两个Widget的过渡过程绘制出来了,在过渡完成之后再真正的切换QStackedWidget的显示界面。
如上图所示,线1的坐标就是QPropertyAnimation所计算出来的,线1
将整个QStackedWidget分成左、右两个部分,左边绘制widget1
(QStackedWidget中当前显示的Widget)的右半部分,右边绘制widget2
(QStackedWidget中将要显示的Widget)的左半部分,因为线1
是变化的,这就产生了我们看到的切换动画了
源码
接着上面的原理,用代码来说明,在这之前一些知识点:
- Widget::render(QPixmap) :这个函数的作用是将Widget的内容渲染成一张图片,这就为我们绘制两个Widget提供了可能
- QPainter::drawPixmap(QRectF target, QPixmap &pixmap, QRectF source):这个函数的作用是将上面渲染得到的图片绘制出来,参数说明:
- target:要绘制的目标区域
- pixmap:要绘制的图片
- source:要绘制的图片的区域
- 综上:也就是说将pixmap的source部分绘制到目标(这里是QStackedWidget)的target部分
上面的两个函数说完了,感兴趣的可以自己去学习下绘图知识
下面看代码,首先是头文件:
class QAnimationStackedWidget : public QStackedWidget{ Q_OBJECTpublic: explicit QAnimationStackedWidget(QWidget *parent = 0); 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; //下一个要切换的索引};
上面是自定义的QAnimationStackedWidget类,里面持有一个QPropertyAnimation对象,它的初始化部分:
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::next(){ //如果正在动画,那么return if( isAnimation ) { return; } isAnimation = true; widgetCount = count(); int c = currentIndex(); //计算下一页的索引 nextIndex = (c + 1) % widgetCount; //隐藏当前的widget widget(c)->hide(); //开始动画并设置间隔和开始、结束值 QRect g = geometry(); int x = g.x(); int width = g.width(); animation->setStartValue(width); animation->setEndValue(0); animation->setDuration(duration); animation->start();}
上面的代码是开启动画,因为QPropertyAnimation::start()方法调用之后会发射valueChanged()信号,所以我们可以接收到改变了的值:
void QAnimationStackedWidget::valueChanged_slot(QVariant value){ currentValue = value; update();}
update又会触发paintEvent函数,所以我们在paintEvent里面可以将过渡的效果绘制出来:
void QAnimationStackedWidget::paintEvent(QPaintEvent *e){ if( isAnimation ) { QPainter paint(this); //绘制当前Widget paintPrevious(paint, currentIndex()); //绘制下一个widget paintNext(paint, nextIndex); }}
paintPrevious:
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()); paint.drawPixmap(r1, pixmap, r2);}
paintNext():
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()); paint.drawPixmap(r1, nextPixmap, r2);}
动画完成,真正开始切换界面:
void QAnimationStackedWidget::animationFinished(){ isAnimation = false; widget(currentIndex())->show(); setCurrentIndex(nextIndex);}
至此,效果已经出来了,下面看看效果:
资料
在实现这个效果的过程中有参考过这个博客:
http://www.itdadao.com/articles/c15a360863p0.html
源码
源码地址:点我下载
- 带切换动画的QStackedWidget
- 带标签的viewpager自动切换+滑动切换+点击标签切换 带动画效果
- 带缩放动画效果的图片切换的功能实现
- 【Android进阶】自定义带动画切换效果的ViewPager
- (Android)自动切换的ViewPager广告栏(带动画和切换速率控制)
- PySide的QStackedWidget例子
- QStackedWidget
- QStackedWidget
- QStackedWidget
- QStackedWidget
- QStackedWidget
- QStackedWidget
- 去除android activity自带切换动画
- 设置switch开关切换,带动画效果
- iOS - 多控制器切换(带滑动动画)
- ViewPager轮播切换带动画效果
- viewfilper的切换动画,activity切换动画
- fleep滑动切换tab(切换带动画)
- mysql insert锁机制
- win10 vs2015 libs3 编译
- 将checkbox选中的值写入数组
- fflush和fsync的一些总结
- 时间显示的工具类
- 带切换动画的QStackedWidget
- Linux-shell-Sed命令的用法
- Ruby Selenium 用法
- POJ 1068 Parencodings 已被翻译
- [Android]从BroadcastReceiver到Activity的通信
- 第14周 oj 3 进制转换(十进制转二进制)(数组)
- C# ,十七章 项目案例: QQ用户信息管理系统
- 用python绘制图形的一些使用技巧
- 数据库mysql