windows编程技术10GDI编程3动画Word格式.docx

上传人:b****5 文档编号:17364944 上传时间:2022-12-01 格式:DOCX 页数:24 大小:526.06KB
下载 相关 举报
windows编程技术10GDI编程3动画Word格式.docx_第1页
第1页 / 共24页
windows编程技术10GDI编程3动画Word格式.docx_第2页
第2页 / 共24页
windows编程技术10GDI编程3动画Word格式.docx_第3页
第3页 / 共24页
windows编程技术10GDI编程3动画Word格式.docx_第4页
第4页 / 共24页
windows编程技术10GDI编程3动画Word格式.docx_第5页
第5页 / 共24页
点击查看更多>>
下载资源
资源描述

windows编程技术10GDI编程3动画Word格式.docx

《windows编程技术10GDI编程3动画Word格式.docx》由会员分享,可在线阅读,更多相关《windows编程技术10GDI编程3动画Word格式.docx(24页珍藏版)》请在冰豆网上搜索。

windows编程技术10GDI编程3动画Word格式.docx

#defineIDB_BITMAP4134

#defineIDB_BITMAP5135

#defineIDB_BITMAP6136

#defineIDB_BITMAP7137

#defineIDB_BITMAP8138

#defineIDB_BITMAP9139

#defineIDB_BITMAP10140

10.1.2添加控件、创建对话框类

为对话框资源添加图片控件:

打开对话框资源,在控件工具箱中选图片控件(PictureControl)工具,在对话框的适当位置添加图片控件,设置其“ID”属性值为“IDC_ANI”,修改“Type”属性为(在其下拉式列表框中选中)“Bitmap”,再在“Image”属性的下拉式列表框中选中“IDB_BITMAP1”位图资源,则该位图绘显示在图片控件中。

为了控制动画的播放,需要添加一个即可表示开始动画又可表示停止动画的按钮(初始标题为“开始动画”),可设置其ID为“IDC_ANI_START_STOP”。

为了让用户选择动画的速度,可以添加静态文本提示框“每秒帧数:

”和文本编辑框(IDC_N),在后面的10.1.6小节中还会添加滑块控件(SliderControl,IDC_SLIDER_N)。

创建该对话框资源所对应的对话框类CDukeDlg。

10.1.3添加类变量、装入与删除位图

在对话框类的定义(头文件)中添加若干类变量:

CBitmap*m_pBmp[10];

//位图指针数组

BITMAPm_bs;

//位图结构变量

boolm_bStarted;

//判别动画是否启动(初始化为false)

intm_nCurFrame,//当前帧号(初值为0)

m_nFramesPerSecond;

//每秒帧数(初值为10)

为CDukeDlg类添加(重写型)消息响应函数OnInitDialog,在该函数中(也可以在构造函数中)创建位图对象并装入位图资源,然后获取位图结构(其中的位图宽和高用于BitBlt函数),并初始化其他类变量,最后设置编辑控件的初值(粗体部分为新加的):

BOOLCDukeDlg:

OnInitDialog()

{

CDialog:

OnInitDialog();

//TODO:

在此添加额外的初始化

for(inti=0;

i<

10;

i++){//装入位图资源

m_pBmp[i]=newCBitmap;

m_pBmp[i]->

LoadBitmap(IDB_BITMAP1+i);

}

m_pBmp[0]->

GetBitmap(&

m_bs);

//获取位图结构

m_bStarted=false;

//设置已开始动画为假

m_nCurFrame=0;

//设置初始的当前帧为0

m_nFramesPerSecond=10;

//设置初始动画速度为每秒10帧

SetDlgItemInt(IDC_N,m_nFramesPerSecond);

//设置编辑框初值

returnTRUE;

//returnTRUEunlessyousetthefocustoacontrol

//异常:

OCX属性页应返回FALSE

其中,语句m_pBmp[i]->

中的IDB_BITMAP1+i用到了Duke位图资源ID的连续性。

为了避免内存泄漏,还需要为对话框类添加析构函数,并在该函数中删除位图对象:

CDukeDlg:

~CDukeDlg()

i++)deletem_pBmp[i];

10.1.4启动/停止动画(设置/删除计时器)

为按钮IDC_ANI_START_STOP添加单击消息响应函数:

voidCDukeDlg:

OnBnClickedAniStartstop(){

在此添加控件通知处理程序代码

if(m_bStarted){//已开始动画

m_bStarted=false;

KillTimer

(1);

//取消计时器

//设置按钮文本为“开始动画”

SetDlgItemText(IDC_ANI_START_STOP,L"

开始动画"

);

else{//未开始动画

m_bStarted=true;

//设置已开始动画为真

m_nCurFrame=0;

////设置当前帧为0

//获取编辑框中的帧速值

m_nFramesPerSecond=GetDlgItemInt(IDC_N);

if(m_nFramesPerSecond<

=0)//限制最小帧速值为1

m_nFramesPerSecond=1;

elseif(m_nFramesPerSecond>

100)//最大帧速值为100

m_nFramesPerSecond=100;

//用调整后帧速值重新设置编辑框的内容

SetDlgItemInt(IDC_N,m_nFramesPerSecond);

//利用帧速值来设置计时器

SetTimer(1,(UINT)(1000.0/m_nFramesPerSecond+0.5),NULL);

//设置按钮文本为“停止动画”

停止动画"

其中:

●m_bStarted为布尔型类变量,用于判断动画是否已经开始播放。

在构造函数中初始化为假,在用户按了开始/停止动画按钮后取反。

●m_nCurFrame为整数型类变量,用于记录当前所要显示的位图序号,初始化为0。

●m_nFramesPerSecond也为整数型类变量,用于记录当前的每秒帧数(帧速值,范围可设为1~100)。

●SetDlgItemText函数,用于动态修改按钮上的文本。

●SetTimer用于设置计时器,它是CWnd的成员函数(所以也可在其派生的视图类和对话框类中使用),其函数原型为:

UINTSetTimer(UINTnIDEvent,UINTnElapse,

void(CALLBACKEXPORT*lpfnTimer)(HWND,UINT,UINT,DWORD));

⏹nIDEvent为此计时器的编号。

因为一个应用程序可以设置多个计时器,为了在响应时区分它们,必须各有一个编号。

简单程序的计时器一般只有一个,所以取nIDEvent=1即可。

⏹nElapse为间隔时间,单位为毫秒(1/1000秒)。

可用表达式(UINT)(1000.0/m_nFramesPerSecond+0.5),从每秒帧数计算出间隔时间的毫秒数。

⏹lpfnTimer为应用程序提供的处理WM_TIMER消息的回调函数,一般取为NULL,这时WM_TIMER消息由CWnd派生类的对应消息响应函数来处理。

●KillTimer用于删除计时器,它也是CWnd的成员函数,其函数原型为:

BOOLKillTimer(intnIDEvent);

在设置了计时器后,系统会按指定的时间间隔发送WM_TIMER消息给应用程序窗口,程序员可在计时器消息响应函数OnTimer中作需要的处理,在本程序中是显示当前位图。

10.1.5绘制动画(响应计时器消息)

为CDukeDlg类的WM_TIMER消息添加响应函数:

OnTimer(UINTnIDEvent){

在此添加消息处理程序代码和/或调用默认值

CDC*pDC=GetDlgItem(IDC_ANI)->

GetDC();

//获取图片框DC

CDCdc;

//定义内存DC

dc.CreateCompatibleDC(pDC);

//创建兼容DC

dc.SelectObject(m_pBmp[m_nCurFrame]);

//选入当前帧位图

pDC->

BitBlt(0,0,m_bs.bmWidth,m_bs.bmHeight,&

dc,

0,0,SRCCOPY);

//显示当前帧位图

m_nCurFrame++;

//当前帧加一(设置下一次要显示的位图序号)

m_nCurFrame%=10;

//当前帧余10(避免超出位图数组,实现循环)

OnTimer(nIDEvent);

结果如图10-3所示。

图10-3Duke动画

10.1.6滑块控件的使用

为了使用户能够利用鼠标快速修改每秒帧数的值,我们在对话框中添加了一个滑块控件(SliderControl)(可将其ID值设为“IDC_SLIDER_N”)。

对应的MFC类为CSliderCtrl,它是直接从CWnd派生的类:

CObject→CCmdTarget→CWnd→CSliderCtrl。

可以在对话框类中定义一个CSliderCtrl的类指针变量:

CSliderCtrl*m_pSlider;

然后在对话框类的初始化函数中获得滑块控件对象的指针,并设置其取值范围为1~100,再设置其滑块的当前位置(注意:

粗体代码必需位于SetDlgItemInt之前):

OnInitDialog(){

……

m_pSlider=(CSliderCtrl*)GetDlgItem(IDC_SLIDER_N);

m_pSlider->

SetRange(1,100);

SetPos(m_nFramesPerSecond);

为了能在用户移动滑块时,动态修改编辑控件中的值,需要为对话框类添加水平滚动消息(WM_HSCROLL)的响应函数OnHScroll:

OnHScroll(UINTnSBCode,UINTnPos,

CScrollBar*pScrollBar){

SetDlgItemInt(IDC_N,m_pSlider->

GetPos());

OnHScroll(nSBCode,nPos,pScrollBar);

同样,为了在用户修改编辑控件中的值时,动态改变滑块的位置,还需要为对话框类添加编辑控件的EN_CHANGE消息响应函数:

OnEnChangeN(){

SetPos(GetDlgItemInt(IDC_N));

注意,如果滑块初始化的代码位于SetDlgItemInt之后,则会造成此语句中的m_pSlider指针无效。

10.1.7CImageList类

上面的位图动画,也可以使用MFC的图像列表类CImageList来实现,代码会更简单一些。

CImageList类是CObject的直接派生类:

CObject→CImageList

1.成员函数

CImageList类的常用成员函数有:

●构造函数:

CImageList();

●创建函数:

BOOLCreate(intcx,intcy,UINTnFlags,intnInitial,intnGrow);

●添加函数:

intAdd(CBitmap*pbmImage,COLORREFcrMask);

●绘制函数:

BOOLDraw(CDC*pDC,intnImage,POINTpt,UINTnStyle);

2.例子

可在动画对话框类中添加如下代码:

//类变量(头文件)

intm_nCurFrame,m_nFramesPerSecond;

CImageListimgList;

//初始化(OnInitDialog函数)

BITMAPbs;

CBitmapbmp;

bmp.LoadBitmap(IDB_BITMAP1);

bmp.GetBitmap(&

bs);

imgList.Create(bs.bmWidth,bs.bmHeight,ILC_COLOR8,10,0);

imgList.Add(&

bmp,RGB(0,0,0));

for(inti=1;

i++){

bmp.DeleteObject();

bmp.LoadBitmap(IDB_BITMAP1+i);

imgList.Add(&

bmp.DeleteObject();

//绘图(OnTimer函数)

imgList.Draw(pDC,m_nCurFrame,CPoint(0,0),ILD_NORMAL);

//OnBnClickedAniStartStop、OnHScroll和OnEnChangeN函数同前

10.1.8过程框图

下面分别给出使用位图数组和CImageList类来实现固定位图动画的主要过程框图。

1.使用位图数组

图10-4是使用位图数组实现固定位图动画的主要过程框图。

图10-4使用位图数组实现固定位图动画的主要步骤

2.使用图像列表

图10-5是使用CImageList类实现固定位图动画的主要过程框图。

图10-5使用CImageList类实现固定位图动画的主要步骤

10.2图形动画

在前面(参见8.5.3小节)利用鼠标进行交互绘图时,我们就已经实现了简单的图形动画——动态画直线、矩形或椭圆等,用户可通过鼠标对绘图位置坐标和图形大小进行交互式选择。

具体做法是,用灰色点线笔在同一个位置异或画两次一样的图形——第一次画图,第二次擦除。

快速不断地在不同的地方画擦,就达到了动画的效果。

即图形动画的原理就是边擦边画。

如果要画的不再是简单的线状图形,而是复杂的面状图,则异或画图方法就不再有效。

因为异或会大大改变窗口中原有图形的色彩,这是用户所不能容忍的。

可用的解决方法是,擦除(或保存)要绘图的区域,然后再绘制新图形(并恢复原区域的图形)。

具体的实现方法有两种——直接绘图和缓冲绘图。

10.2.1直接绘图

利用直接绘图方法,来产生动画的原理很简单,但是会存在讨厌的闪烁现象。

1.原理

通过不断地擦除(要绘图的区域)和绘制(新图形)动态图形而产生动画效果。

可以使用CDC类的画填充矩形的函数(使用白色刷):

voidFillRect(LPCRECTlpRect,CBrush*pBrush);

来擦除指定矩形区域。

例如:

pDC->

FillRect(&

rect,newCBrush(RGB(255,255,255)));

然后,再在该矩形区域内绘制新图形。

pDC->

SelectObject(&

pen);

//选入画边框的笔

brush);

//选入画填充色的刷

Ellipse(&

rect);

//绘制填充椭圆

下面是一个在白色背景上动态画伸缩填充椭圆的例子,需要创建一个传统单文档MFC应用程序。

主要代码片段如下:

1)在视图类中定义若干类变量:

boolshrink;

//用于判断伸缩

intr,w,h,//当前椭圆的短轴半径和宽高

R,W,H,//最大椭圆的短轴半径和宽高

xc,yc;

//椭圆的中心坐标

CPenpen;

//绘制椭圆边框的笔(与刷同色)

CBrushbrush,whiteBrush;

//绘制椭圆内部的刷和删除原椭圆的白刷

2)在视图类的构造函数中,设置初值、构造笔和刷:

shrink=true;

//初始为缩小

COLORREFgreenCol=RGB(0,150,0),//定义绿色

whiteCol=RGB(255,255,255);

//定义白色

pen.CreatePen(0,0,greenCol);

//实心单像素宽的绿色笔

brush.CreateSolidBrush(greenCol);

//实心绿色刷

whiteBrush.CreateSolidBrush(whiteCol);

//实心白色刷

3)在某个菜单项的事件处理函数中计算并设置初值、启动计时器:

CRectrect;

GetClientRect(&

//获取当前客户区矩形

W=rect.Width();

H=rect.Height();

r=R=min(W,H)/2;

//初始为最大椭圆

w=W/2;

h=H/2;

xc=W/2;

yc=H/2;

SetTimer(1,10,NULL);

//可设置不同的时间间隔,或者让用户来设置

4)在计时器的消息响应函数OnTimer中,擦除并绘制椭圆,调整半径:

CDC*pDC=GetDC();

//擦除

if(shrink){//对膨胀不需要擦除

CRectrect(xc-w,yc-h,xc+w,yc+h);

FillRect(rect,&

whiteBrush);

//调整半径

if(shrink){

w--;

h--;

r--;

//缩小1像素

if(r==0)shrink=false;

//转换成放大

}else{

w++;

h++;

r++;

//放大1像素

if(r==R)shrink=true;

//转换成缩小

Ellipse(xc-w,yc-h,xc+w,yc+h);

ReleaseDC(pDC);

运行结果如图10-6所示。

图10-6伸缩填充椭圆

运行该程序后会发现,存在明显的闪烁现象,这主要是由收缩时的擦除操作所造成的。

解决办法是,采用内存DC进行缓冲绘图。

10.2.2缓冲绘图

在前面资源位图动画的绘制过程中,我们已经采用了缓冲(buffering)方法来显示位图:

BitBlt(0,0,bs.bmWidth,bs.bmHeight,&

d

展开阅读全文
相关资源
猜你喜欢
相关搜索

当前位置:首页 > 高中教育 > 英语

copyright@ 2008-2022 冰豆网网站版权所有

经营许可证编号:鄂ICP备2022015515号-1