使用定时器显示GIF动画的ATL控件实现

本文介绍了如何在IM软件中实现GIF动画的插入和显示,对比了HTML控件和RichEdit控件的优缺点。作者分享了自己通过创建ATL控件,使用定时器重绘GIF动画的方法,解决了闪烁和重影问题,提供了详细的开发步骤和代码示例。
摘要由CSDN通过智能技术生成

最近在做一个IM软件,IM软件非常重要的功能就有动态表情的插入和显示。实现GIF图片显示的方法主要有两种,一种是通过HTML控件,一种是通过RichEdit控件。HTML控件显示GIF动画的效率是很高的,但是可操控性不好(比如不允许表情修改尺寸,插入后自动滚动到聊天记录窗口的底部等);RichEdit的可操控性就好得多了,但是插入和显示GIF动画就比较麻烦。

网上流传的向CRichEditCtrl中插入GIF动画的方法不外乎有两类:一类是使用第三方的控件(如QQ的ImageOle或Gif89a),另一类是自己实现一个ATL控件,在控件中实现GIF的重绘。

我也用过QQ的ImageOle,能成功插入GIF动画,还是挺高兴的,但不久就发现了ImageOle的致命问题,插入的GIF动画会闪烁,这样的东西给用户用还不被骂啊,不行,一定得解决这个问题,不断地使用谷歌和度娘,提到的唯一解决办法就是设置CRichEditCtrl的风格为WS_EX_TRANSPARENT(透明),然后在WM_ERASEBKGND中绘制白色背景,这样试了一下,的确不闪了,其他绘制很正常,但是GIF透明背景中还会保留以前绘制的帧,就是所谓的重影,这个用户也不能接受。

没办法,只能将方向转向自己实现一个类似于ImageOle的ATL控件,对于没有什么COM开发经验的我来说,连怎么创建ATL控件的工程都不会,但是不会也得会,谁让我已经走上了这条不归路呢,经过不断折腾,终于知道怎么创建工程了。

然而待解决的问题还有一箩筐呢,第一个要解决的就是如何绘制GIF!绘制方法也基本上只有两种,开线程和定时器。

开线程的方法我感觉效率有点低,而且开销也有点大(也许你们有不同的想法);于是决定有定时器,但是ATL无窗口控件怎么使用定时器呢,使用定时器需要有一个窗口句柄,这个好解决,创建一个隐藏的小窗口就有了嘛;那么怎么定时,所有的GIF使用同一个定时器还是不同的GIF使用不同的定时器呢,从用户体验上来说,肯定是不同GIF使用不同的定时器较好,那么定时的时间怎么办,因为GIF各帧之间的持续时间可能是不同的,这个也好办,先将定时器时间设置为第一帧,定时时间到时再重新设置成第二帧……这样就行了,而且使用定时器的效率比开线程要高,开销也要小得多。

总结一下,我们的方法就是自己实现一个显示GIF动画的ATL控件,GIF绘制方法使用定时器的方式,对每一帧设置不同的定时时间,定时时间到时更换帧。

接下来好戏上场了,先一步步来创建一个空的ATL控件工程吧,我使用的是VS2010。首先点击“文件”,“新建”,“项目”,选择ATL项目,取个名字(比如叫EmotionOle),点击确定,如下图所示。


第一个对话框,无条件点击下一步。


在这个对话框中,勾上“允许合并代理/存根代码”,为了创建出来只有一个项目,否则有两个项目,对于我这种有强迫症的人来说不能忍受;如果你想使用MFC的东东(比如使用CDC、CBitmap类等)时,勾上“支持MFC”;把“支持COM+ 1.0”和“支持部件注册器”也勾上,点击完成,VS会自己帮你创建好项目,等它创建完成。

 

在EmotionOle项目上点击鼠标右键,选择“添加”,“类”,如下图所示。

选择“ATL控件”,点击添加。

在“简称”中填写控件名,比如“EmotionOle”,其他的输入框中内容会自动填上,除了ProgID,在ProgID中随便填点什么吧,比如“EmotionOle.EmotionOle”,如下图所示,点击下一步。

这个对话框中勾上“连接点”,因为可能需要处理一些事件,点击下一步。

这个对话框中一切保持默认即可,点击下一步。

这个对话框也一样,保持默认,点击下一步。

还是一样,保持默认,点击完成即可。

这时ATL控件已经创建好了,现在这个项目是可以编译,也可以插入到RichEdit中,只不过只是一张没有实际意义的图片,接下来是重头戏上场的时间了,我们来创建显示GIF。

显示GIF首先得加载图片吧,先添加加载图片的方法,我们使用从文件读取的方式,也可使用HGLOBAL和IStream的方式。

转到类视图,在IEmotionOle上点击鼠标右键,选择“添加”,“添加方法”,如下图所示。

 

输入方法名,参数特性的“in”可勾可不勾,勾了只是有一个空的宏说明是入参而已,参数类型选择BSTR,参数名随便写吧,点击添加,如下图所示。

如果还想添加参数再继续上面的步骤,我们这里只添加一个路径参数就可以了,点击完成。


这时候CEmotionOle类中已经自动添加了Load函数,我们使用Gdiplus来读取和绘制GIF图片,所以需要在EmotionOle.h文件中包含GdiPlus.h文件,同时别忙了在项目启动时调用GdiplusStartup,在项目退出时调用GdiplusShutdown,如下图所示。

 

接下来添加几个成员变量:

Image *m_pImage; // GDI+的Image对象指针,保存读取的GIF图片

LONG *m_pFrameTimes; // 各帧的持续时间数组,单位为毫秒

UINT m_nCurFrame; // 当前帧序号

UINT m_nFrameCount; // 总帧数

 

下面这个变量的作用相信大家也看出来了,就是为了使用定时器而创建的隐藏窗口,CHiddenWnd的声明和定义在后面介绍。

CHiddenWnd

评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值