借助 CPictureEx 和 CPictureExWnd 为您的 MFC 和 ATL 项目添加 GIF 动画






4.95/5 (76投票s)
2001年10月5日
5分钟阅读

1368697

33518
一个用于显示 GIF 动画以及更多内容的类。提供 MFC 和 ATL 版本!
引言
CPictureEx
类最初是为了一个 MFC 项目编写的,该项目
需要支持 JPEG 和 GIF 格式的横幅广告。静态横幅广告使用 OleLoadPicture
函数和 IPicture
接口显示并不难,但处理 GIF 动画则完全是另一回事。
在搜索了无数的互联网链接后,我发现只有一个免费选项——CodeGuru 上 George Tersaakov 的一个 COM 对象。不幸的是,它在显示我的一些测试 GIF 时存在问题。当然,我可以购买第三方库,但那样的话,我就得为我实际上不需要的额外功能付费。我决定尝试自己写一个类。基本思路是将 GIF 分割成单独的帧,然后使用熟悉的 OleLoadPicture
和 IPicture
组合来显示这些帧。在仔细阅读了 GIF87a 和 GIF89a 的规范后,我编写了这个类。请注意,CPictureEx
不仅可以显示 GIF(包括 GIF 动画),还可以显示 JPEG、BMP、WMF、ICO 和 CUR(即 OleLoadPicture
支持的所有格式)。之后,我又编写了该类的 ATL 版本。
如何使用 MFC 版本(CPictureEx)
在您的对话框中添加一个静态文本控件或图片控件(分组框也可以);将该控件的 ID 改为类似 IDC_MYPICTURE
的名称;使用类向导将一个成员变量(例如 m_Picture
)与添加的控件关联,类别 - 控件,变量类型 - CStatic
;在对话框的头文件中,将变量类型从 CStatic
替换为 CPictureEx
(不要忘记 #include "PictureEx.h"
,并将 PictureEx.h 和 PictureEx.cpp 添加到您的项目中);在 OnInitDialog
(或您喜欢的任何地方)中,添加以下代码行
if (m_Picture.Load(_T("mypicture.gif"))) m_Picture.Draw();
坐下来,享受动画吧 :)
您也可以将 CPictureEx
当作标准的 CStatic
来处理,并通过手动调用 CPictureEx::Create()
,然后调用 CPictureEx::Load
和 CPictureEx::Draw
来创建它(如果您的宿主窗口不是对话框,则必须这样做)。
如何使用 ATL 版本(CPictureExWnd)
要使用 ATL 版本(CPictureExWnd
),请遵循相同的步骤,但不要使用类向导,而是手动在您的类中添加一个 CPictureExWnd
类型的变量,并将以下代码添加到您的 WM_INITDIALOG
处理函数中
HWND hWnd = GetDlgItem(IDC_MYPIC);
if (hWnd) m_wndBanner.SubclassWindow(hWnd);
之后,您可以调用 CPictureExWnd::Load()
和 CPictureExWnd::Draw()
。当然,您也可以直接调用 CPictureExWnd::Create
——CPictureExWnd
只是一个带有额外窗口过程功能的窗口。
接口函数
BOOL Load(...)
- 加载 GIF 并准备对象以供绘制;BOOL Draw()
- 绘制图片或继续动画;void Stop()
- 停止动画;void UnLoad()
- 停止动画并释放所有资源;void SetBkColor(COLORREF)
- 设置透明区域的填充颜色;COLORREF GetBkColor()
- 获取当前填充颜色;BOOL IsGIF()
- 如果当前图片是 GIF,则返回TRUE
;BOOL IsAnimatedGIF()
- 如果当前图片是 GIF 动画,则返回TRUE
;BOOL IsPlaying()
- 如果当前图片正在显示动画,则返回TRUE
;SIZE GetSize()
- 返回图片的尺寸;int GetFrameCount()
- 返回当前图片的帧数;BOOL GetPaintRect(RECT *lpRect)
- 返回当前绘制矩形;BOOL SetPaintRect(const RECT *lpRect)
- 设置当前绘制矩形;
CPictureEx[Wnd]::Load
有三个版本
BOOL Load(LPCTSTR szFileName);
此版本从文件 szFileName
加载图片。函数的返回值指示加载是否成功。
BOOL Load(HGLOBAL hGlobal, DWORD dwSize);
此 Load
获取一个全局内存块的句柄,该内存块使用 GlobalAlloc
和 GMEM_MOVEABLE
标志分配。函数**不释放**内存,因此请不要忘记使用 GlobalFree
释放它。返回值指示加载是否成功。
BOOL Load(LPCTSTR szResourceName,LPCTSTR szResourceType);
该函数获取一个包含图片的资源名称和一个资源类型名称。例如
m_Picture.Load(MAKEINTRESOURCE(IDR_MYPIC),_T("GIFTYPE"));
加载图片后,使用 CPictureEx[Wnd]::Draw()
函数进行显示。如果图片是 GIF 动画,该函数将启动一个后台线程来执行动画;如果图片是静态图片,则会立即使用 OleLoadPicture
/IPicture
显示。您可以随时使用 CPictureEx[Wnd]::Stop()
函数停止启动的线程。如果您想不仅停止动画,还要释放所有相关资源,请使用 CPictureEx[Wnd]::UnLoad()
(CPictureEx[Wnd]::Load()
会自动调用 UnLoad()
)。
默认情况下,图片的背景填充为 COLOR_3DFACE
(对话框窗口的背景色)。如果您需要更改图片的背景,请在调用 CPictureEx[Wnd]::Load()
后调用 CPictureEx[Wnd]::SetBkColor(COLORREF)
。
版本历史
- 1.0 (2001 年 8 月 7 日) - 初始发布;
- 1.1 (2001 年 9 月 6 日) - 类的 ATL 版本;
- 1.2 (2001 年 10 月 31 日) - 各种 bug 修复
- 修复了 MFC 版本类中多模块应用程序加载 GIF 资源的问题。感谢 Ruben Avila-Carretero 发现此问题。
- 在
ThreadAnimation()
中删除了可等待计时器,现在CPictureEx[Wnd]
可以在 Win95 上运行。感谢 Alex Egiazarov 和 Wayne King 的建议。 - 修复了使用
SetBkColor
时的视觉瑕疵。感谢 Kwangjin Lee 发现此问题。
- 1.3 (2001 年 11 月 18 日) - bug 修复和新功能
- 修复了 DC 泄漏问题。每次
UnLoad()
都会泄漏一个 DC(忘记在CPictureExWnd::PrepareDC()
函数末尾放置ReleaseDC()
)。 - 现在可以使用
CPictureEx[Wnd]::SetPaintRect(const LPRECT)
函数设置剪裁矩形。LPRECT
参数告诉类应该显示图片的哪个部分。如果未设置剪裁rect
,则显示整个图片。感谢 Fabrice Rodriguez 的建议。 - 增加了对
Stop
/Draw
的支持。现在您可以Stop()
一个 GIF 动画,然后再次Draw()
它,它将从停止的帧继续动画。您还可以通过IsPlaying()
函数知道 GIF 当前是否正在播放。 - 删除了 math.h 并将
m_bExitThread
设置为 volatile。感谢 Piotr Sawicki 的建议。
- 修复了 DC 泄漏问题。每次