程序设计实践 -预处理和EGG库

上传人:抢*** 文档编号:243133944 上传时间:2024-09-16 格式:PPT 页数:53 大小:649KB
返回 下载 相关 举报
程序设计实践 -预处理和EGG库_第1页
第1页 / 共53页
程序设计实践 -预处理和EGG库_第2页
第2页 / 共53页
程序设计实践 -预处理和EGG库_第3页
第3页 / 共53页
点击查看更多>>
资源描述
单击以编辑,母版标题样式,单击以编辑母版文本样式,第二级,第三级,第四级,第五级,*,工程、预处理和,EGG,库,提纲,预处理命令,预处理指令,#include,预处理指令,#define:,符号常量,预处理指令,#define,:宏,条件编译,2. Egg,图形库说明,预处理指令,#define,:宏,#define,用来定义,符号常量(用符号表示的常量)。,宏(用符号定义的操作)。,宏,宏用来替代一个字符串,类似于符号常量,宏在预处理时被替换字符串取代。,不带参数的宏:预处理程序就像处理符号常量一样处理不带参数的宏。,带参数的宏:先用替换文本取代参数,然后再把宏展开。,预处理指令,#define,:宏,带参数的宏定义格式:,#define,标识符,(,形式参数表,),字符串,形式参数表由逗号分割开的标识符组成,这些标识符在字符串中出现。,如:,#define PI 3.14159 /,常量定义,#define,CIRCLE_AREA(x),(PI*(x)*(x),#define,MAX(x,y),(x)(y)?(x):(y),#define,NUL(x,y),(x)*(y),预处理指令,#define,:宏,宏调用格式:,标识符(实在参数表),如:,area=CIRCLE_AREA(3+4),;,宏在预处理时被展开:,1.,替换参数,:,文件中如果出现宏调用,CIRCLE_AREA(3+4),,则字符串中的,x,都用,3+4,替代,;,2.,用字符串取代程序中的宏调用。,语句,area=CIRCLE_AREA(3+4),;在预处理 时将被展开成,area=(3.14159*(3+4)*(3+4),;,(3.14159*(3+4)*(3+4),预处理时被展开,预处理指令,#define,:宏,需要注意的是,在宏名和括起参数的括号之间绝对不能有空格。此外,为了避免在翻译宏时产生歧义,宏体和参数也应该用括号括起来。例如,象下例中这样定义宏,CIRCLE_AREA,是不正确的:,define CIRCLE_AREA(x) PI*x*x,如:,int a=3,b=4;,语句,area=CIRCLE_AREA(a+b),;,将被展开成,3.14159*a+b*a+b,;,预处理指令,#define,:宏,使用宏还是函数,宏与函数相比有一个明显的优势,即它比函数效率更高,(,并且更快,),,因为宏可以直接在源代码中展开,而调用函数还需要额外的开销。,但是,宏一般比较小,无法处理大的、复杂的代码结构,而函数可以。,此外,宏需要逐行展开,因此宏每出现一次,宏的代码就要复制一次,这样你的程序就会变大,而使用函数不会使程序变大。,条件编译,使编译器能够按照不同条件编译不同的程序部分,产生不同的目标代码文件。,两种条件编译:使用常量表达式判断、使用宏定义名判断,条件编译,条件编译,1.,使用常量表达式判断,(,共,3,种,),#if,整型常量表达式,文本,1,#else,其他文本,#endif,#if,整型常量表达式,文本,1,#endif,第,1,种情况,第,2,种情况,首先求常量表达式的值,然后根据常量表达式值是否,为,0,进行,下面的条件编译。在第,2,种情况中,如果该表达式的值非,0,,则编译文本,1,,否则编译其他文本。,#if,整型常量表达式,1,文本,1,#elif,整型常量表达式,2,文本,2,#else,其他文本,#endif,第,3,种情况,条件编译,让编译器不编译某一段代码:,#if 0,不编译的代码,#endif,以后若想让编译器编译该段代码,只需要将,0,改成,1,条件编译,2.,使用宏定义名判断,#ifdef,标识符,文本,1,#else,文本,2,#endif,#ifndef,标识符,文本,1,#endif,如果定义了标识符为宏(即使宏体为空),则为真,编译,#ifdef,后面的文本;否则编译,#else,后面的文本,#ifdef,标识符,文本,1,#endif,条件编译,#ifdef,标识符是,#if defiend,(标识符)的缩写,#ifndef,标识符是,#if !defiend,(标识符)的缩写,条件编译,调试阶段 ,若想打印变量的值,则代码如下:,#define DEBUG /,定义宏,宏体为空,#ifdef DEBUG,printf(,“,variable x=%dn,”,,,x),;,printf(,“,variable y=%dn,”,,,y),;,#endif,完成调试后,可以去掉,#define,指令,这样就会在编译过程中忽略上述两条,printf,语句。,条件编译,#include,#define DEBUG /,定义宏,main(),int age;,char name20;,printf(input your agen);,scanf(%d,printf(input your namen);,scanf(%s,name);,条件编译,#ifdef DEBUG,printf(input age is:%dn,age);,#endif,#undef DEBUG /,取消宏定义,#ifdef DEBUG,printf(input name is:%sn,name);,#endif,system(pause);,return 0;,input your age,30,input your name,john,input age is:30,请按任意键继续,. . .,条件编译,怎样避免多次包含同一个头文件,?,在创建一个头文件时,你可以用,#define,指令为它定义一个唯一的标识符名称。你可以通过,#ifndef,指令检查这个标识符名称是否已被定义,如果已被定义,则说明该头文件已经被包含了,就不要再次包含该头文件;反之,则定义这个标识符名称,以避免以后再次包含该头文件。,猴子选大王,NodeType.h:,#ifndef _NODETYPE_H,#define _NODETYPE_H,struct listNode,int data;,struct listNode *nextPtr;,;,typedef struct listNode LISTNODE;,typedef LISTNODE * LISTNODEPTR;,#endif,#include “NodeType.h”,#include “NodeType.h”,main.c,编译遇到第,1,条,include,指令,由于,_NODETYPE_H,未被定义,因此该头文件被包含,,_NODETYPE_H,被定义;编译遇到第,2,条,include,指令时,由于,_NODETYPE_H,已定义,因此该头文件将不再被包含,其他,预处理指令,#error,,,#pragma,运算符,#,和,#,行号,#line,预定义的符号常量,宏,assert,提纲,使用工程组织多个源文件,预处理命令,Egg,图形库说明,图形库函数,EGG,简介,可以把代码编译成库供其他人员调用。其他人员看不到源代码。,两种库:静态链接库和动态链接库,静态链接库,在链接(,link,)的时候被连接到,.exe,文件(,.LIB,中的代码被包含到,.exe,文件中了),导致应用程序比较大。,当,.LIB,版本升级时,需要对调用该,LIB,的程序重新编译。,.exe,LIB,图形库函数,EGG,简介,.DLL,(,Dynamic Link Library,),:,动态链接库,DLL,是一个包含可由多个程序同时使用的代码和数据的库。例如,在,Windows,操作系统中,,Comdlg32 DLL,执行与对话框有关的常见函数。因此,每个程序都可以使用该,DLL,中包含的功能来实现,“,打开,”,对话框。,事先不被连接到,.exe,文件,在运行期才会被调用。,1.exe,DLL,调用,调用,2.exe,图形库函数,EGG,简介,动态链接库是分两步链接进程序中的,:,首先,在编绎的时候,链接器查找出程序需要的所有符号(函数,变量等等),然后链接进程序当中或者程序的另一个共享链接库当中。,动态链接库中的目标文件并没有固化进可执行文件。替代的是,当程序运行的时候,由系统的一个程序(叫做动态装载器,dynamic libraries,)检查程序需要哪些动态链接库,然后把它们装入内存并且与内存中的程序关联。,图形库函数,EGG,简介,DLL,的优点,使用较少的资源当多个程序使用同一个函数库时,,DLL,可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在,Windows,操作系统上运行的程序。,推广模块式体系结构,DLL,有助于促进模块式程序的开发。,简化部署和安装当,DLL,中的函数需要更新或修复时,部署和安装,DLL,不要求重新建立程序与该,DLL,的链接。此外,如果多个程序使用同一个,DLL,,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方,DLL,时,此问题可能会更频繁地出现。,图形库函数,EGG,简介,Egg,提供,2,个静态链接库和,1,个头文件:,egg.lib /,静态链接库,eggd.lib /,静态链接库,egg.h,图形库函数,EGG,简介,EGG,绘图功能:,绘制直线,绘制曲线(正圆和椭圆),绘制字符串,贴图:,.bmp,文件,设置画笔的颜色和线条粗细,移动画面的某些部分(动画),图形库函数,EGG,简介,坐标系统,采用我们最熟悉的平面直角坐标系,左下角是坐标原点,,X,坐标向右递增,,Y,坐标向上递增,单位是厘米,坐标原点,图形库函数,EGG,简介,画笔当前位置,在,Egg,中有一个画笔,尽管我们看不到它,但它确确实实存在。画笔指向位置的坐标就是画笔的当前位置,简称画笔位置。所有绘图操作都是从画笔位置开始落笔绘图,按照绘图要求移动画笔,并把最后提笔结束的位置作为新的画笔位置。,画笔的初始位置是画面的左上角,,并非坐标原点(左下角)。,画笔初始位置,画笔相关函数,void,MovePen (double x, double y),移动画笔位置到新的绝对坐标,void,OffsetPen(double dx, double dy),按相对当前位置的位移移动画笔位移画笔位置,double,GetPenXPos (void),得到画笔的,X,坐标,double,GetPenYPos (void),得到画笔的,Y,坐标,图形库函数,EGG,简介,初始化,只要调用一个函数,EggStart(),就完成所有初始化,Egg,平台的工作。,void EggStart(double fWidth, double fHeight);,参数:绘图窗口的宽和高,单位厘米。,你不需要考虑,Egg,的结束问题。只要程序正常退出,,Egg,占用的所有资源都会被自动释放。,图形库函数,EGG,简介,直线,void,DrawLine (double dx, double dy),从画笔当前位置,按照参数指定的位移画一条直线。,位移可以为正(沿,X/Y,坐标的正方向绘制)、也可为负,(,沿,X/Y,坐标的负方向绘制),void line(void),EggStart(,5,5,);,/,初始化,DrawLine(5, -5);,/,绘制直线,WaitForExit(); /,等待用户关闭窗口,图形库函数,EGG,简介,正圆曲线,void DrawArc(double r, double dStart, double dSweep);,r,:曲线所在圆的半径,单位厘米。,dStart,:曲线开始点在圆周上的角度(即画笔在圆周上的角度),dSweep,:曲线沿圆周按逆时针方向扫过的角度。,如:,DrawArc(2, 45, 90);,图形库函数,EGG,简介,DrawArc(2, 45, 90);,圆半径为,2,的圆可以有多个,但是画笔位置在圆周上角度为,45,的圆只有一个。画笔位置、圆半径以及角度唯一确定一个圆。,void yuan1(void),EggStart(4,4);,OffsetPen(4,-2);/,相对移动,DrawArc(2,0,360);,WaitForExit();,void yuan1(void),EggStart(4,4);,OffsetPen(4,-,1,);/,相对移动,DrawArc(2,0,360);,WaitForExit();,画笔初始位置,void yuan1(void),EggStart(4,4);,OffsetPen(,2,-2);/,相对移动,DrawArc(2,0,360);,WaitForExit();,图形库函数,EGG,简介,椭圆曲线,void DrawEllipticalArc(double rx, double ry, double dStart, double dSweep);,参数,dStart,和,dSweep,的含义与,DrawArc,完全相同。,rx,是该椭圆在,x,轴的半径,,ry,是在,Y,轴的半径。,图形库函数,EGG,简介,字符串,void DrawString(char* pString);,例如,要输出,Hello World,,使用如下代码:,DrawString(Hello World);,字符串的左上角位于当前的画笔位置,输出后画笔位置移动到字符串的右上角。,Hello World,输出前画笔位置,输出后画笔位置,图形库函数,EGG,简介,贴图,Egg,支持,.bmp,文件的贴图,使用下面函数:,void DrawBitmap(char* lpszFilename);,参数是,bmp,文件名,例如要贴当前目录下的,“,beauty.bmp,”,文件,可以使用下面语句:,DrawBitmap(beauty.bmp);,位图的左上角位于画笔当前位置,贴图后,画笔当前位置移动到位图的右上角。,图片,输出前画笔位置,输出后画笔位置,void yuan1(void),EggStart(4,4);,OffsetPen(2,-2);,DrawArc(2,0,360);,MovePen(2,2);,DrawString(hello);,DrawBitmap(pic.bmp);,WaitForExit();,图形库函数,EGG,简介,画笔颜色和宽度,函数,SetPen(),改变画笔的颜色和宽度,从此都用指定的颜色和宽度绘画各种图形、文字,直到下次调用相关函数为止。,void SetPen(unsigned long color, double fWidth);,fWidth,是宽度,单位厘米。,color,是颜色,取值见具体宏定义。,如果只想单独改变颜色或宽度,可以调用,void SetPenColor (unsigned long color),void SetPenWidth(double fWidth),动画实现,盘子:白色窗口,egg,:任何图形都是画在一个,egg,上,可以有多个,egg,,但每个,egg,都是相对独立的,可以绘画、移动任何一个,egg,,而不会影响其它的,egg,。移动时只能以,egg,为单位进行移动,因此要一起移动的内容得画在同一个,egg,上。,egg,的大小与调用,EggStart(),时指定的大小一致,并且覆盖整个盘子(盘子是,Egg,图形窗口的昵称),但它初始状态是透明的。,可以画多个,egg,,当两个蛋重合,后下的蛋会覆盖先下的蛋。使用,ChangeEggLayer(),可以改变,egg,的层次,调整互相之间的覆盖关系。,需要特别注意的是,在,egg,上绘画时,所采用的坐标系是每个,egg,自己的独立坐标,而不是盘子坐标。也就是说,绘画时,不需要考虑,egg,在盘子内的位置(,egg,会移动),,egg,自己的左下角永远是坐标原点。,如何下蛋:,每次调用,LayEgg(),都会生成一个新的,egg,,并把这个,egg,的句柄返回给你。,HEGG LayEgg(void);,执行完,EggStart(),后,便已经偷偷建立了一个,egg,,所有的绘图操作,都是在这个,egg,上进行的。当,LayEgg(),后,再执行绘图操作,就是在新的,egg,上绘图了。,如何设置活动蛋:,绘图和移动都是在活动蛋上进行的;,如果想回头在旧,egg,上绘图,可以使用,void SetActiveEgg(HEGG hEgg),函数,将旧的,egg,变成活动蛋,因此,需要把每次,LayEgg(),的返回值(,egg,的句柄)保存下来,从而将旧蛋变成活动蛋;,#include egg.h,#define NUMBER_OF_EGG 5,int main(void),HEGG hEggsNUMBER_OF_EGG;,int i;,EggStart(10,5);,for (i=0; iNUMBER_OF_EGG; i+),hEggsi = LayEgg(); DrawArc(i+1, 180, 180);/,在当前活动的蛋上画一个半圆,WaitForExit(); /,等待用户关闭窗口,return 0;,由于每个蛋是透明的,所以能看到所有蛋上的半圆,如何动蛋,移动是在活动蛋上进行的。移动一个蛋时,该蛋上所有的图形都会一起动。,如果只是想动整个图形的一部分(如电梯、小火车),则该部分一定要在一个独立的,egg,上绘制。,void MoveEgg(double x, double y);,在盘子上移动活动,egg,到盘子内的坐标,处,void OffsetEgg(double dx, double dy);,在盘子上把活动,egg,移动,(dx,dy),位移,/,画,5,个能分别动起来的半圆,void donghua1(void),HEGG hEggsNUMBER_OF_EGG;,int i;,EggStart(10,5);,/,画,5,个不同半径的半圆,for (i=0; iNUMBER_OF_EGG; i+),hEggsi = LayEgg();,DrawArc(i+1, 180, 180);,/,让,5,个半圆分别移动,i = 0;,while (WaitFor(100),SetActiveEgg(hEggsi);,OffsetEgg(NUMBER_OF_EGG - i - 1) * 0.1, 0);,if (i NUMBER_OF_EGG - 1),i+;,else,i = 0;,/,画,5,个能,同时,动起来的半圆,void donghua2(void),HEGG hEggsNUMBER_OF_EGG;,int i;,EggStart(10,5);,SetAutoUpdate(0);,/,设置不自动更新屏幕,for (i=0; iNUMBER_OF_EGG; i+),hEggsi = LayEgg();,DrawArc(i+1, 180, 180);,Update();,/,也可以不要,i = 0;,while (WaitFor(100), /,定时器,SetActiveEgg(hEggsi);,OffsetEgg(NUMBER_OF_EGG - i - 1) * 0.1, 0);,if (i NUMBER_OF_EGG - 1),i+;,else,i = 0;,Update();,/,更新,Egg,窗口,将,5,个,egg,的分时移动模拟为同时动,4.3-Egg,定时器,1,int WaitFor(unsigned int uMillisecond);,这是一种很简单的定时器。调用此函数后,你的程序在,uMillisecond,毫秒内将什么也不做,静静地等待,WaitFor(),函数的返回。在需要延时的场合,这个函数是很好用的。但当用户关闭窗口的时候,它会立即返回,返回值为,0,。此时,我们要停止正在做的事情,转入退出流程。,例:,/,让,5,个,egg,分别移动,#include “egg.h”,/,先定义,5,个,egg,,代码略,i = 0;,while (WaitFor(100), /,每隔,0.1,秒会有一个半圆移动,SetActiveEgg(hEggsi);,OffsetEgg(NUMBER_OF_EGG - i - 1) * 0.1, 0);,if (i NUMBER_OF_EGG - 1) i+;,else i = 0;,4.4-Egg,定时器,2,void StartTimer(unsigned int uMillisecond);,void StopTimer(void);,这两个函数比,WaitFor(),稍微复杂一点儿,但它们的控制能力更精准,而且可以和其它输入完全配合(,WaitFor(),在等待的时候,用户的所有输入动作都无效,除了关闭窗口)。,StartTimer(),后,每隔,uMillisecond,毫秒,都会产生一个,TIMER,事件,可以用,WaitForEvent(),捕获这个事件,进而做相应的周期工作。不再需要定时事件时,调用,StopTimer(),停止它。,4.4-Egg,定时器,2,EVENT_TYPE ev;.,StartTimer(500);,while (ev = WaitForEvent(),!= EXIT), switch (ev) ,case TIMER:,/,响应周期事件,break;,case KEYDOWN:,/,响应按键按下事件,break;,case KEYUP:,/,响应按键抬起事件,break; ,StopTimer();,建议:定时器函数可以用在动画输出部分,控制对电梯画面的刷新。,
展开阅读全文
相关资源
正为您匹配相似的精品文档
相关搜索

最新文档


当前位置:首页 > 图纸专区 > 小学资料


copyright@ 2023-2025  zhuangpeitu.com 装配图网版权所有   联系电话:18123376007

备案号:ICP2024067431-1 川公网安备51140202000466号


本站为文档C2C交易模式,即用户上传的文档直接被用户下载,本站只是中间服务平台,本站所有文档下载所得的收益归上传人(含作者)所有。装配图网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对上载内容本身不做任何修改或编辑。若文档所含内容侵犯了您的版权或隐私,请立即通知装配图网,我们立即给予删除!