自从gif动画格式推出这十几年来,可是忙坏了C/C++的程序员。远的不说,就说这几年吧,各种方法可谓五花八门,有的直读文件,一行一行不厌其烦的分析;有的使用IPicture,大把大把的玩接口;有的封装成COM,谁也不知道他怎么实现的......现在有了GDI+,大家更忙活了,所以我写了这篇文章。
其实只要使用.net框架封装好的几个函数,就能轻松搞定了,这里要用到的工具是VS.net2003。
第一步:新建一个.Net窗体工程
其实只要使用.net框架封装好的几个函数,就能轻松搞定了,这里要用到的工具是VS.net2003。
第一步:新建一个.Net窗体工程
第二步:添加成员变量和消息(就是行为和外观啦),只要双击空白处系统就会自动填写默认函数,添加图中的三个函数就够了。
第三步:添加成员变量image及在Form1_Load中初始化
private: Image *image; private: System::Void Form1_Load(System::Object * sender, System::EventArgs * e) { //按路径读入文件 image=Image::FromFile(L"测试图片.GIF"); } private: System::Void Form1_Closed(System::Object * sender, System::EventArgs * e) { if(image) image->Dispose(); }
第四步:好了,动画文件已经读入,现在的任务是把它显示出来
private: System::Void Form1_Paint(System::Object * sender, System::Windows::Forms::PaintEventArgs * e) { //在Form1_Paint中启用动画,这个函数的功能是读取图片中每个对象的时间信息,然后每到一次时间就调用一次OnPaintGIF ImageAnimator::Animate(image, new EventHandler(this,OnPaintGIF)); //显示图片 e->Graphics->DrawImage(0,0,image->Width,image->Height); //将图片按照时间间隔向后翻一页 ImageAnimator::UpdateFrames(image); } private: System::Void OnPaintGIF(Object* sender, EventArgs* e) { //时间到啦,该显示下一张图啦,置显示区域无效 this->Invalidate(); }
到此,已经可以正确显示GIF格式的动画了,简单吧,才几行就解决了。
........不过嘛,呵呵,大家仔细观察会发现,图片一闪一闪的,很不好看.....那怎么办呢?用双缓冲方法?非也,根本就不是一码事!图片闪铄的问题几乎每天都能在论坛上看到,我在这里顺便说一下原因。数据量大时的闪动是因为计算机来不及载入数据,这时可以用双缓冲法;但是数据量不大时图片闪动是因为当程序置屏幕无效时框架会用背景色来擦除,这样就会闪一下,这时用双缓冲法就无效了。后者在MFC中我们可以响应OnEraseBkgnd()来解决;可是在.net中找不到这个消息,怎么办呢?其实只要避开屏幕无效就好了,请往下看:
private: Image *image; Graphics *p;//添加一个用来显示的变量 private: System::Void Form1_Load(System::Object * sender, System::EventArgs * e) { image=Image::FromFile(L"测试图片.GIF");//按路径读入文件 p=Graphics::FromHwnd(this->Handle);//按窗口句柄创建Graphics ImageAnimator::Animate(image, new EventHandler(this,OnPaintGIF));//启动动画 } private: System::Void Form1_Closed(System::Object * sender, System::EventArgs * e) { if(p) p->Dispose(); if(image) image->Dispose(); } private: System::Void OnPaintGIF(Object* o, EventArgs* e) { p->DrawImage(image,0,0,image->Width,image->Height);//显示图片 ImageAnimator::UpdateFrames();//将图片向后翻一页,由于OnPaintGIF()本身就是按时间启动的,所以UpdateFrames()要不要参数无所谓了 } private: System::Void Form1_Paint(System::Object * sender, System::Windows::Forms::PaintEventArgs * e) { //呵呵,这个可以不要了,在属性页中删除所有文字即可自动删除代码 }
是不是也很简单啊?这样就把图像的闪烁问题也解决了。部分图片的效果如下,图像文件打包在代码文件夹里了,代码包里的程序可以读取多种图片并且可以点击任意位置拖动