C++工具箱——动画类之基类
Posted 牧秦丶
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C++工具箱——动画类之基类相关的知识,希望对你有一定的参考价值。
OK,我们已经讨论了单件和定时器了,该来点真格的了。这次我们来看看如何通过前面所述的定时器实现动画。我目前想到的动画有大小更改、Alpha 透明度更改、窗口位置更改等几种,后续会逐步加上。
我们先来思考动画的实质。动画其实就是通过定时器,一步步逼近一个期望结果的过程。我们期望的动画类是这样的:
1、接口简单、使用方便;
2、可扩展。比如我们后续加上新的动画类时不必太费力;
3、添加新动画类时不必操心动画共有的部分;(如计时器、回调等等)
一个动画有以下共有性质:
1、两次动画间的时间间隔(ms 为单位);
2、动画是否已经开启了;
3、整个动画展示完成后的回调(可选);
4、动画对象的管理。
第四个尤为重要,因为我们可能在一个如何一个函数(全局函数、类成员方法、某一个线程处理函数)中启用一个动画,如果还需手动管理动画对象的生命周期的话,那就太不Fashion了!(你可以思考下如果让你来设计,你会怎么设计这个动画的基类)
好的,我们来看我设计的动画基类,如果你有更好的点子,可以找我沟通。你可能需要定时器、Boost相关的知识。如下:
/**
* \\file frameanimation.h
* \\author arnozhang
* \\date 2012.9.13
* \\brief 窗口动画基类.
*/
#ifndef __FRAME_ANIMATION_BASE_H__
#define __FRAME_ANIMATION_BASE_H__
#include "wnd.h"
#include "timer.h"
namespace Util
template <typename _Co_Animation> class CFrameAnimation
public:
// 动画完成回调.
typedef _Co_Animation this_class;
typedef boost::function<void(void)> AnimationFinishCallback;
// 获取一个动画对象.
static _Co_Animation& GetAnimation(CWnd* targetFrame)
return *(new _Co_Animation(targetFrame));
// 启动动画.
void StartAnimation()
if (m_bAnimationStarted || !m_targetFrame)
return ;
m_bAnimationStarted = TRUE;
if (_PrepareAnimation())
Util::SetTimerCallback(
m_targetFrame,
m_dwTimeInterval,
TIMER_CALL_BIND(this_class, AnimationHandler_Bind_Proc)
);
// 设置动画时间间隔.
void SetTimeInterval(
DWORD dwTimeInteval = DEFAULT_ANIMATION_TIME_INTERVAL
)
m_dwTimeInterval = dwTimeInteval;
// 设置动画帧数.
void SetFrameCount(DWORD dwFrameCnt)
m_dwFrameCount = dwFrameCnt;
// 设置整个动画完成后的回调.
void SetFinishedCallback(const AnimationFinishCallback& finishedCbk)
delete m_pFinishedCallback;
m_pFinishedCallback = new AnimationFinishCallback(finishedCbk);
private:
// 动画处理器.
void AnimationHandler_Bind_Proc()
_AnimationHandler();
protected:
virtual bool _PrepareAnimation() = 0;
virtual void _AnimationHandler() = 0;
// 动画执行完毕.
void _AnimationFinished()
// 清除计时器.
Util::KillTimerCallback(m_targetFrame);
// 调用完成回调.
if (m_pFinishedCallback)
(*m_pFinishedCallback)();
// 删除动画对象.
delete this;
CFrameAnimation(CWnd* targetFrame)
m_targetFrame = targetFrame;
m_dwTimeInterval = DEFAULT_ANIMATION_TIME_INTERVAL;
m_dwFrameCount = 0;
m_bAnimationStarted = FALSE;
m_pFinishedCallback = 0;
virtual ~CFrameAnimation()
delete m_pFinishedCallback;
CWnd* m_targetFrame;
DWORD m_dwFrameCount;
private:
AnimationFinishCallback* m_pFinishedCallback;
DWORD m_dwTimeInterval;
BOOL m_bAnimationStarted;
static const int DEFAULT_ANIMATION_TIME_INTERVAL = 30;
;
#define BIND_ANIMATION_FINISHED_PROC(class_name, method_name) \\
boost::bind(&class_name::method_name, this)
/*namespace Util ends here.*/
#endif /*__FRAME_ANIMATION_BASE_H__*/
我们定义了一个抽象模版基类 CFrameAnimation。其中模版参数 _Co_Animation 是实现动画类的具体类(如 CFrameBlendAnimation 、 CFrameSizeAnimation 等)。如果我们要实现新的动画类,只需继承该类就行了,并且重写 _PrepareAnimation和 _AnimationHandler这两个虚方法即可。其中 _PrepareAnimation为开启动画前的初始化及准备工作——因为不同的动画类有不同的属性和初始化方法; _AnimationHandler正如其名,是动画处理过程,因为不同的动画类对应的动画处理也不尽相同。这两个方法都是 模版方法。
我们将 CFrameAnimation的构造和析构均设为protected属性(CFrameAnimation的子类亦如此),让它们只能通过静态方法GetAnimation得到一个动画对象,让动画对象只能在堆上构造,然后在动画完成后通过delete this; 这句来释放掉——完全保证了动画对象生命周期的独立管理,不需要用户操一点心思。
我们定义了一个 _AnimationFinished方法,每个新的动画类在_AnimationHandler中完成所有动画的处理后,必须调用该函数删除定时器、释放资源。考虑 DEFAULT_ANIMATION_TIME_INTERVAL 为什么为30?因为人眼中,当动画、游戏等帧数为每秒30帧左右的时候,看起来是连贯的。所以这个值为 1000ms / 30 帧,大约等于30。所以,动画对象的 SetTimerInterval 方法一般不需要调用,我们一般通过SetFrameCount 方法来控制动画的播放帧数。
比如我们实现了一个CFrameBlendAnimation来完成窗口的透明度渐变,那么使用方法也很简单:
#include "frameblendanimation"
void animationFinished()
cout<<"hello! Animation Finished!"<<endl;
void foo()
CWnd wnd;
wnd.Create();
// ...
CFrameBlendAnimation& animation = CFrameBlendAnimation::GetAnimation(&wnd);
animation.SetStartAlpha(255);
animation.SetEndAlpha(0);
// 设置播放帧数.
animation.SetFrameCount(10);
// 完成回调可要可不要,根据需求来.
animation.SetFinishedCallback(animationFinished);
// 启动动画.
animation.StartAnimation();
可以看出,我们只需通过 GetAnimation 方法获取一个动画对象,然后做相应的设置,最后调用 StartAnimation启动动画就行了,完全不用我们操心。解耦的好处在这里得到了充分体现。
下一章将实现一个实现上述窗口透明度渐变的动画类 CFrameBlendAnimation。将会有一份实现好的源代码示例可供下载。大家也可趁机想想如何实现这样一个CFrameBlendAnimation类。
以上是关于C++工具箱——动画类之基类的主要内容,如果未能解决你的问题,请参考以下文章
一点一滴,成材之基! Linux后门Trojan Horse检测工具