首页 > 技术知识 > 正文

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; } }
<

猜你喜欢