收藏 分享(赏)

程序设计实践7w -工程、预处理和EGG库.ppt

上传人:dzzj200808 文档编号:3351694 上传时间:2018-10-17 格式:PPT 页数:87 大小:1.52MB
下载 相关 举报
程序设计实践7w -工程、预处理和EGG库.ppt_第1页
第1页 / 共87页
程序设计实践7w -工程、预处理和EGG库.ppt_第2页
第2页 / 共87页
程序设计实践7w -工程、预处理和EGG库.ppt_第3页
第3页 / 共87页
程序设计实践7w -工程、预处理和EGG库.ppt_第4页
第4页 / 共87页
程序设计实践7w -工程、预处理和EGG库.ppt_第5页
第5页 / 共87页
点击查看更多>>
资源描述

1、提纲,使用工程组织多个源文件 预处理命令 Egg图形库说明,2.模块化和工程,模块的定义 一般把用一个名字就可调用的一段程序称为“模块”,如子程序、函数等。 模块的基本属性: 功能:描述该模块实现什么功能 逻辑:描述模块内部怎么做 状态:该模块使用时的环境和条件 除了基本属性,还需描述模块的内部和外部特性 模块的外部特性:模块的模块名、参数表 模块的内部特性:完成其功能的程序代码和仅供该模块内部使用的数据 通常是先确定模块的外部特性,再确定其内部特性。,1.使用工程组织多个源文件,函数是最小的模块,若干个紧密相关的函数可以组成更大的模块源文件。 一条好的原则就是保持模块的紧凑性即在同一个源文件

2、中只包含那些在逻辑上与其相关的函数。,1.使用工程组织多个源文件,模块化:把程序划分成独立命名且可独立访问的模块,每个模块完成一个子功能,所有模块集成起来构成的整体可完成用户的所有需求。模块化意义 降低了系统的复杂性,使系统容易修改和重用; 推动系统各部分的并行开发,提高开发效率。,复杂问题 较小问题高层模块 从整体上把握问题,隐蔽细节,分解,1.使用工程组织多个源文件,使用工程来组织多个源文件。 将功能紧密相关的若干个函数组成单独的源文件。 对应于每一个提供通用功能的源文件,建立头文件。 #include “ListNode.h” 自定义的头文件,该文件在工程所在目录下 #include “

3、E:/temp/MyType.h“ 自定义的头文件,该文件不在工程所在目录下 #include 标准库函数头文件,1.使用工程组织多个源文件,实例:猴子选大王 源文件的分割 头文件的使用 使用工程组织多个源文件,在DEV-C+集成开发环境中: 1.创建工程文件(.dev)文件/新建/工程,在弹出窗口中选择Console Application 2、往项目中增加源文件(.c)工程/新建单元 新建一个源文件加到项目中 或者 工程/ 添加 将已有的一个源文件加到项目中 3、编译、链接、运行,查看结果运行/编译 编译项目中所有源文件或者运行/编译当前文件 编译当前源文件 或者运行/编译运行编译项目中所

4、有源文件、链接、运行,DEV-C+下工程的创建,一.新建工程1.点击菜单:文件-新建-工程.,DEV-C+下工程的创建,2. 在弹出窗口的Basic页中选择Console Application,输入工程名称,选择是c工程,点击确定。,DEV-C+下工程的创建,3. 此时弹出对话框,要求指定工程存放路径(如G:temptestProject)。选择好路径后点击保存。,DEV-C+下工程的创建,4. 此时系统自动加入main.c文件如下。里面代码是系统自动生成的。,DEV-C+下工程的创建,二. 往工程中增加已创建的其他文件将linkNode.h、link.c和link.h三个文件拷贝到工程所在

5、目录G:temptestProject下然后点击菜单 工程-添加,DEV-C+下工程的创建,在弹出的对话框中选择要添加的源文件。然后点击打开。,DEV-C+下工程的创建,此时在工程管理(Project)页中出现了加入这3个文件,DEV-C+下工程的创建,在工程管理页中鼠标左键点击link.c,则右边的代码区出现该文件的源代码。,DEV-C+下工程的创建,DEV-C+下工程的创建,保存main.c在右边的代码区选择main.c,然后Ctrl+S进行保存,此时弹出对话框,询问保存的目录。,三. 编译文件若选择编译(CtrlF9),则编译当前工程中的所有文件。若只是想单独编译一个文件,则选择 编译当

6、前文件(Shift+ CtrlF9)。,DEV-C+下工程的创建,DEV-C+下工程的创建,编译成功后,在工程所在目录G:temptestProject中包含文件如下,双击.exe即可运行程序。 也可使用Execute菜单下的Run菜单运行程序。 .dev是工程文件。双击该文件即可在DevC+环境中打开工程。,四、在当前工程中新建一个文件如果要新建文件并将其添加到工程中,则选择菜单 工程-新建单元,DEV-C+下工程的创建,此时将加入一个文件(未命名3)。选择保存时,指定该文件的名字和保存路径(一般和工程在同一路径下)。如下图所示,DEV-C+下工程的创建,五.从工程中移除一个文件。如下图所示

7、。注意:此时该文件在磁盘里还是存在,只是不包含在当前工程中了。,DEV-C+下工程的创建,DEV-C+下工程的创建,注意:添加一个已存在的文件到工程中时,该文件也可以不位于工程所在路径下。假设工程位于D:tempproject目录下,要加入工程的linkNode.h、link.h和link.c位于其他目录,则编译后工程所在目录如下,并没有将上述三个文件复制到工程目录下(其时在文件.dev中记录着上述3个文件的磁盘路径),在VC6开发环境中: 1. 点击File-New弹出菜单(如下图),VC6环境下工程的创建,2.选择Projects选项卡,选择Win32 Console Applicatio

8、n,在Project name文本框输入工程名(如elevator),在Location文本框选择路径如(如C:test)(见下图)点击OK,VC6环境下工程的创建,3.点击Finish(如下图),VC6环境下工程的创建,4.点击OK(如下图),VC6环境下工程的创建,5.把所有源文件 例elevator.c、elevator.h文件拷贝到工程所在目录下(如C:TEST) 。,VC6环境下工程的创建,6.点击左下角的FileView(如下图红色圈所示),再鼠标右键点击Source Files(如下图红色箭头所示), 选择Add Files to Folder,选择文件将elevator.c加入

9、到Source Files目录, 鼠标右键点击Header Files,选择Add Files to Folder,选择文件将elevator.h加入到Header Files目录(结果如下图),VC6环境下工程的创建,7.选择主菜单Project-Settings(工程-设置)出对话框(如下图),VC6环境下工程的创建,VC6环境下工程的创建,8. 点击左边树状导航栏elevator,点击右边选项卡Link,找到Object/library modules:文本框,在最后添加两项Msimg32.lib、egg.lib(如图)点击OK,9.这样就可以编写自己的主程序了,比如在Source Fi

10、le目录下建立main.c文件,main.c应包含 前面的elevator.h(如下图),VC6环境下工程的创建,提纲,使用工程组织多个源文件 预处理命令 Egg图形库说明,预处理指令 #include 预处理指令 #define:符号常量 预处理指令 #define:宏 条件编译,提纲,预处理指令 #define:宏,#define用来定义 符号常量(用符号表示的常量)。 宏(用符号定义的操作)。 宏 宏用来替代一个字符串,类似于符号常量,宏在预处理时被替换字符串取代。 不带参数的宏:预处理程序就像处理符号常量一样处理不带参数的宏。 带参数的宏:先用替换文本取代参数,然后再把宏展开。,预处理

11、指令 #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) ,则

12、字符串中的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);将被

13、展开成 3.14159*a+b*a+b;,预处理指令 #define:宏,使用宏还是函数 宏与函数相比有一个明显的优势,即它比函数效率更高(并且更快),因为宏可以直接在源代码中展开,而调用函数还需要额外的开销。 但是,宏一般比较小,无法处理大的、复杂的代码结构,而函数可以。 此外,宏需要逐行展开,因此宏每出现一次,宏的代码就要复制一次,这样你的程序就会变大,而使用函数不会使程序变大。,条件编译 使编译器能够按照不同条件编译不同的程序部分,产生不同的目标代码文件。 两种条件编译:使用常量表达式判断、使用宏定义名判断,条件编译,条件编译,1.使用常量表达式判断(共3种),#if 整型常量表达式文本

14、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 标识符

15、文本1 #endif,如果定义了标识符为宏(即使宏体为空),则为真,编译#ifdef后面的文本;否则编译#else后面的文本,#ifdef 标识符文本1 #endif,条件编译,#ifdef 标识符是 #if define(标识符)的缩写 #ifndef 标识符是 #if !define(标识符)的缩写,条件编译,调试阶段 ,若想打印变量的值,则代码如下: #define DEBUG /定义宏,宏体为空 #ifdef DEBUGprintf(“variable x=%dn”,x);printf(“variable y=%dn”,y); #endif 完成调试后,可以去掉#define 指令,这

16、样就会在编译过程中忽略上述两条printf语句。,条件编译,#include #define DEBUG /定义宏 main() int age;char name20;printf(“input your agen“);scanf(“%d“,条件编译,#ifdef DEBUG printf(“input age is:%dn“,age); #endif#undef DEBUG /取消宏定义#ifdef DEBUG printf(“input name is:%sn“,name); #endifsystem(“pause“);return 0; ,input your age 30 input

17、 your name john input age is:30 请按任意键继续. . .,条件编译,怎样避免多次包含同一个头文件?在创建一个头文件时,你可以用#define指令为它定义一个唯一的标识符名称。你可以通过#ifndef指令检查这个标识符名称是否已被定义,如果已被定义,则说明该头文件已经被包含了,就不要再次包含该头文件;反之,则定义这个标识符名称,以避免以后再次包含该头文件。,猴子选大王 NodeType.h:,#ifndef _NODETYPE_H #define _NODETYPE_H struct listNodeint data;struct listNode *nextPt

18、r; ;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,#program 运算符#和# 行号#line 预定义的符号常量 宏assert,提纲,使用

19、工程组织多个源文件 预处理命令 Egg图形库说明,图形库函数EGG简介,可以把代码编译成库供其他人员调用。其他人员看不到源代码。 两种库:静态链接库和动态链接库 静态链接库 在链接(link)的时候被连接到.exe文件(.LIB中的代码被包含到.exe文件中了),导致应用程序比较大。 当.LIB版本升级时,需要对调用该LIB的程序重新编译。,.exe,图形库函数EGG简介,.DLL(Dynamic Link Library):动态链接库 DLL 是一个包含可由多个程序同时使用的代码和数据的库。例如,在 Windows 操作系统中,Comdlg32 DLL 执行与对话框有关的常见函数。因此,每个

20、程序都可以使用该 DLL 中包含的功能来实现“打开”对话框。 事先不被连接到.exe文件,在运行期才会被调用。,1.exe,调用,调用,2.exe,图形库函数EGG简介,动态链接库是分两步链接进程序中的: 首先,在编绎的时候,链接器查找出程序需要的所有符号(函数,变量等等),然后链接进程序当中或者程序的另一个共享链接库当中。 动态链接库中的目标文件并没有固化进可执行文件。替代的是,当程序运行的时候,由系统的一个程序(叫做动态装载器 dynamic libraries)检查程序需要哪些动态链接库,然后把它们装入内存并且与内存中的程序关联。,图形库函数EGG简介,DLL 的优点 使用较少的资源 当

21、多个程序使用同一个函数库时,DLL 可以减少在磁盘和物理内存中加载的代码的重复量。这不仅可以大大影响在前台运行的程序,而且可以大大影响其他在 Windows 操作系统上运行的程序。 推广模块式体系结构 DLL 有助于促进模块式程序的开发。 简化部署和安装 当 DLL 中的函数需要更新或修复时,部署和安装 DLL 不要求重新建立程序与该 DLL 的链接。此外,如果多个程序使用同一个 DLL,那么多个程序都将从该更新或修复中获益。当您使用定期更新或修复的第三方 DLL 时,此问题可能会更频繁地出现。,图形库函数EGG简介,Egg提供2个静态链接库和1个头文件: egg.lib /静态链接库 egg

22、d.lib /静态链接库 egg.h,图形库函数EGG简介,EGG绘图功能: 绘制直线 绘制曲线(正圆和椭圆) 绘制字符串 贴图:.bmp文件 设置画笔的颜色和线条粗细 移动画面的某些部分(动画),图形库函数EGG简介,坐标系统,采用我们最熟悉的平面直角坐标系,左下角是坐标原点,X坐标向右递增,Y坐标向上递增,单位是厘米,坐标原点,图形库函数EGG简介,画笔当前位置 在Egg中有一个画笔,尽管我们看不到它,但它确确实实存在。画笔指向位置的坐标就是画笔的当前位置,简称画笔位置。所有绘图操作都是从画笔位置开始落笔绘图,按照绘图要求移动画笔,并把最后提笔结束的位置作为新的画笔位置。 画笔的初始位置是

23、画面的左上角 ,并非坐标原点(左下角)。,画笔初始位置,画笔相关函数,图形库函数EGG简介,初始化 只要调用一个函数EggStart()就完成所有初始化Egg平台的工作。void EggStart(double fWidth, double fHeight); 参数:绘图窗口的宽和高,单位厘米。 你不需要考虑Egg的结束问题。只要程序正常退出,Egg占用的所有资源都会被自动释放。,图形库函数EGG简介,直线 void DrawLine (double dx, double dy) 从画笔当前位置,按照参数指定的位移画一条直线。 位移可以为正(沿X/Y坐标的正方向绘制)、也可为负(沿X/Y坐标的

24、负方向绘制),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的圆可以有多个,

25、但是画笔位置在圆周上角度为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(); ,

26、图形库函数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,图形库函

27、数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“);W

28、aitForExit(); ,图形库函数EGG简介,画笔颜色和宽度 函数SetPen()改变画笔的颜色和宽度,从此都用指定的颜色和宽度绘画各种图形、文字,直到下次调用相关函数为止。 void SetPen(unsigned long color, double fWidth);fWidth是宽度,单位厘米。color是颜色,取值见具体宏定义。 如果只想单独改变颜色或宽度,可以调用void SetPenColor (unsigned long color)void SetPenWidth(double fWidth),动画实现 盘子:白色窗口 egg:任何图形都是画在一个egg上,每个egg都是

29、相对独立的,可以绘画、移动任何一个egg,而不会影响其它的egg 。只能以egg为单位进行移动。 egg的大小与调用EggStart()时指定的大小一致,并且覆盖整个盘子(盘子是Egg图形窗口的昵称),但它初始状态是透明的。,可以画多个egg,当两个蛋重合,后下的蛋会覆盖先下的蛋。使用ChangeEggLayer()可以改变egg的层次,调整互相之间的覆盖关系。,如何下蛋: 每次调用LayEgg()都会生成一个新的egg,并把这个egg的句柄返回给你。 HEGG LayEgg(void); 执行完EggStart()后,便已经偷偷建立了一个egg,所有的绘图操作,都是在这个egg上进行的。当L

30、ayEgg()后,再执行绘图操作,就是在新的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 = Lay

31、Egg(); DrawArc(i+1, 180, 180); WaitForExit(); /等待用户关闭窗口 return 0; ,如何动蛋 void MoveEgg(double x, double y); void OffsetEgg(double dx, double dy); 这里的(x,y)是egg左上角在盘子内的坐标,(dx,dy)是在盘子坐标系内的位移。 需要特别注意的是,在egg上绘画时,所采用的坐标系是每个egg自己的独立坐标,而不是盘子坐标。也就是说,绘画时,不需要考虑egg在盘子内的位置,egg自己的左下角永远是坐标原点。,/画5个能分别动起来的半圆 void dong

32、hua1(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+;elsei = 0; ,/画5个能同时动起来的半圆 void dongh

33、ua2(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+;elsei = 0

34、;Update(); /更新Egg窗口,将5个egg的分时移动模拟为同时动 ,第8周实验 1)掌握VC6下工程的管理。 2)掌握图形库Egg的库函数使用。,移动的是当前的活动蛋(active egg),该蛋上所有的图形都会一起动。 如果只是想动整个图形的一部分(如电梯、小火车),则该部分一定要在一个独立的egg上绘制。 移动一个egg之前,需要先通过函数void SetActiveEgg (HEGG hEgg)将该egg设置为活动蛋。,4.3-Egg定时器1,int WaitFor(unsigned int uMillisecond); 这是一种很简单的定时器。调用此函数后,你的程序在uMil

35、lisecond毫秒内将什么也不做,静静地等待WaitFor()函数的返回。在需要延时的场合,这个函数是很好用的。但当用户关闭窗口的时候,它会立即返回,返回值为0。此时,我们要停止正在做的事情,转入退出流程。 例:/让5个egg分别移动#include “egg.h” /先定义5个eggi = 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;,4.4-Egg定时器2,void StartTimer

36、(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();,建议:定时器函数可以用在动画输出部分,控制对电梯画面的刷新。,

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

当前位置:首页 > 高等教育 > 大学课件

本站链接:文库   一言   我酷   合作


客服QQ:2549714901微博号:道客多多官方知乎号:道客多多

经营许可证编号: 粤ICP备2021046453号世界地图

道客多多©版权所有2020-2025营业执照举报