在 详解Qt的动画框架(一)介绍了关于Qt动画框架一些基础知识,在这一节中,将会实际的看到有关与动画框架的实现,该案例主要实现的具体是网易云音乐tag的切换,网易云音乐中的切换如图所示:
本文介绍的方法也可以达到这种切换的简易效果。
首先我们需要设计对于动画框架,其需要的动画效果是什么?对于上图,我们需要的是三个tag可以不停的切换,可以抽象为左移以及右移,即一个tag从一个矩形区域,移动到另外的矩形区域,那么对于Tag的承载体选为什么较为合适呢?因为我们仅仅只需要图片的显示,因此QLabel引进足够,而且QLabel继承于QFrame(继承自QWidget),因此拥有geometry的属性,恰恰其类型是QRect,因此可以达到动画效果的所有需求,不需要另外的定制属性(property)。
设计好动画框架后,既可以开始代码实现所有的动作了。以下是头文件的声明定义:
#ifndef MAINWINDOW_H
#define MAINWINDOW_H
#include <QMainWindow>
#include<vector>
using namespace std;
class QLabel;
class QToolBar;
class QPropertyAnimation;
class MainWindow : public QMainWindow
{
Q_OBJECT
protected slots:
void onTriggerAction(QAction *);
public:
MainWindow(QWidget *parent = 0);
~MainWindow();
private:
void moveLeft();
void moveRight();
QRect center_rect;
QRect left_rect;
QRect right_rect;
QLabel *center_label;
QLabel *left_label;
QLabel *right_label;
QPropertyAnimation *moveAnimation;
QPropertyAnimation *moveAnimation_left;
QPropertyAnimation *moveAnimation_right;
int mainCnt;
//下方的2个横线控件
QToolBar *transferBar;
vector<QPixmap> label_group;
};
#endif // MAINWINDOW_H
代码分析:
MainWindow::MainWindow(QWidget *parent)
: QMainWindow(parent)
{
resize(1000,400);
mainCnt=3;
//在widget上画三个矩形框,实现动画切换,第一个大小为200 & 540 左右两边大小均为188*110
for(int label_num=0;label_num<3;label_num++)
{
QPixmap temp_label=QPixmap(":/images/"+QString::number(label_num+1)+".png");
label_group.push_back(temp_label);
}
int width=this->width();
int height=this->height();
/**
设置中心控件的位置以及大小
*/
int pos_x=(width-center_width)/2;
int pos_y=(height-center_hieght)/2;
center_rect.setRect(pos_x,pos_y,center_width,center_hieght);
center_label =new QLabel(this);
center_label->setPixmap(label_group[0]);
//center_label->setScaledContents(true);
center_label->setGeometry(pos_x,pos_y,center_width,center_hieght);
//---------------------------------------------------------------------------------//
/**
设置底部窗口转换的工具栏属性
*/
transferBar = new QToolBar(this);
transferBar->setGeometry(pos_x+center_width/2-40,pos_y+center_hieght+20,90,10);
transferBar->setStyleSheet("background:transparent");
transferBar->setIconSize(QSize(20,5));
for(int actions_num=0;actions_num<2;actions_num++)
{
QAction *action=new QAction(QIcon(":/images/line.png"),"",transferBar);
action->setData(actions_num);
transferBar->addAction(action);
}
connect(transferBar,SIGNAL(actionTriggered(QAction *)),this,SLOT(onTriggerAction(QAction*)));
/**
设置右边控件的位置和大小
*/
right_rect.setRect(pos_x+center_width,pos_y+(center_hieght-margin_height),margin_width,margin_height);
right_label =new QLabel(this);
right_label->setPixmap(label_group[1]);
//right_label->setScaledContents(true);
right_label->setGeometry(pos_x+center_width,pos_y+(center_hieght-margin_height),margin_width,margin_height);
/**
设置左边控件的位置和大小
*/
pos_x=(pos_x-margin_width);
pos_y=pos_y+(center_hieght-margin_height);
left_rect.setRect(pos_x,pos_y,margin_width,margin_height);
left_label =new QLabel(this);
left_label->setPixmap(label_group[2]);
//left_label->setScaledContents(true);
left_label->setGeometry(pos_x,pos_y,margin_width,margin_height);
center_label->raise();
//------------------------------------------------------------------------------//
}代码分析:
1、首先是定位三个矩形框的位置,为了达到和网易的效果,特意量了尺寸,定义如下:
#define center_width 540 #define center_hieght 200 #define margin_width 110 #define margin_height 188骚年,如果感兴趣,可以草图画出来,就可以知道以上关于三个矩形框位置的计算方式是怎么得来的了。当然了,这仅仅只是我的计算方式,可以不予采来,嘻嘻。
2、其次是定位三个QLabel的位置,初始的时候,与三个矩形框保持一致。
3、最后是底部按钮的设计,主要是Icon的设计以及位置,还有toolBar的响应事件。
关键代码在于响应事件的设计,即两个函数moveLeft()以及moveRight();
#define ToLeft 0 #define ToRight 1
void MainWindow::onTriggerAction(QAction *action)
{
int action_num=action->data().toInt();
if (action_num==ToLeft)
moveLeft();
else if(action_num==ToRight)
moveRight();
}
void MainWindow::moveLeft()
{
mainCnt+=1;
moveAnimation_left=new QPropertyAnimation(left_label,"geometry");
moveAnimation_left->setDuration(200);
moveAnimation_left->setStartValue(left_rect);
moveAnimation_left->setEndValue(right_rect);
moveAnimation_left->setEasingCurve(QEasingCurve::Linear);
moveAnimation_left->start();
moveAnimation=new QPropertyAnimation(center_label,"geometry");
moveAnimation->setDuration(200);
moveAnimation->setStartValue(center_rect);
moveAnimation->setEndValue(left_rect);
moveAnimation->setEasingCurve(QEasingCurve::Linear);
moveAnimation->start();
moveAnimation_right=new QPropertyAnimation(right_label,"geometry");
moveAnimation_right->setDuration(200);
moveAnimation_right->setStartValue(right_rect);
moveAnimation_right->setEndValue(center_rect);
moveAnimation_right->setEasingCurve(QEasingCurve::Linear);
moveAnimation_right->start();
/**
方向和label移动的方向恰恰相反
*/
QRect rect(right_rect);
right_rect=center_rect;
center_rect=left_rect;
left_rect=rect;
if(mainCnt==6)
mainCnt=3;
if(mainCnt==4)
{
right_label->raise();
}
else if(mainCnt==5)
{
left_label->raise();
}
else if(mainCnt==1)
{
center_label->raise();
}
}
void MainWindow::moveRight()
{
mainCnt-=1;
moveAnimation_left=new QPropertyAnimation(left_label,"geometry");
moveAnimation_left->setDuration(200);
moveAnimation_left->setStartValue(left_rect);
moveAnimation_left->setEndValue(center_rect);
moveAnimation_left->setEasingCurve(QEasingCurve::Linear);
moveAnimation_left->start();
moveAnimation=new QPropertyAnimation(center_label,"geometry");
moveAnimation->setDuration(200);
moveAnimation->setStartValue(center_rect);
moveAnimation->setEndValue(right_rect);
moveAnimation->setEasingCurve(QEasingCurve::Linear);
moveAnimation->start();
moveAnimation_right=new QPropertyAnimation(right_label,"geometry");
moveAnimation_right->setDuration(200);
moveAnimation_right->setStartValue(right_rect);
moveAnimation_right->setEndValue(left_rect);
moveAnimation_right->setEasingCurve(QEasingCurve::Linear);
moveAnimation_right->start();
/**
方向和label移动的方向恰恰相反
*/
QRect rect(left_rect);
left_rect=center_rect;
center_rect=right_rect;
right_rect=rect;
if(mainCnt==-1)
mainCnt=3;
if(mainCnt==2)
{
left_label->raise();
}
else if(mainCnt==1)
{
right_label->raise();
}
else if(mainCnt==0)
{
center_label->raise();
}
}
代码分析:
1、首先是动画的构造以及初始化:
moveAnimation_left是控制left_label的动画的,左移是从left_rect移动到right_rect的位置,控制属性是geometry,移动的曲线方式是直线型的。
moveAnimation_center是控制center_label动画的,左移是从center_rect的位置移动到left_rect的位置
moveAnimation_right是控制right_label动画的,左移是从right_rect的位置移动到center_rect的位置。
2、其次是需要设置矩形框的位置,其设置效果为为了达到与label的同步,同时达到一种循环王府的效果。这点要重点理解。
3、mainCnt的控制,当达到移动图片的最大数量以后,需要重新开始,同时在不同的移动时,需要label展现效果,即置顶效果,raise();
最后实现的的效果如下:
原文:http://blog.csdn.net/mao19931004/article/details/52143770