《C的菜单设计、图形绘制、动画的播放、乐曲等高级编程技术.doc》由会员分享,可在线阅读,更多相关《C的菜单设计、图形绘制、动画的播放、乐曲等高级编程技术.doc(100页珍藏版)》请在taowenge.com淘文阁网|工程机械CAD图纸|机械工程制图|CAD装配图下载|SolidWorks_CaTia_CAD_UG_PROE_设计图分享下载上搜索。
1、高级编程技术介绍如何利用 TC 系统所提供的相关函数实现菜单设计、图形绘制、动画的播放、乐曲的演奏、汉字的显示、图片的显现等技术,在讲述时,以问题-解答的方式来逐渐阐明。1文本的屏幕输出和键盘输入 . 11.1 文本的屏幕输出.11.2 键盘输入.81.3 问题实现.11 1.4 高级应用菜单实现 .14实验一.232图形显示方式和鼠标输入.232.1 图形显示.232.2 鼠标的使用.522.3 问题实现.58实验二.623屏幕图象与动画技术.633.1 一个简单的实现方法.633.2 利用动态开辟图视口的方法.663.3 利用屏幕图象存储再放的方法.673.4 利用页交替的方法.703.5
2、 问题实现.71实验三.744中断技术 .744.1 编写自己的中断程序.764.2 问题实现.784.3 其它应用硬中断演示秒表程序 .84实验四.875发声技术 .875.1 声音函数.875.2 计算机乐谱.885.3 问题实现.89实验五.936汉字显示技术 .936.1 汉字编码.936.2 问题实现.95实验六.97使用过 Windows 系统的用户都感受到了图形用户界面的直观和高效。所有 Windows 系统的应用程序都拥有相同或相似的基本外观,包括窗口、菜单、工具条、状态栏等。用户只要掌握其中一个,就不难学会其它软件,从而降低了学习成本和难度。而且 Windows 是一个多任务
3、的操作环境,它允许用户同时运行多个应用程序,或在一个程序中同时做几件事情。例如,我们可以边欣赏 MP3 的音乐边 IE 冲浪,可以在运行 WORD 时同时编辑多个文档等。用户直接通过鼠标或键盘来使用应用程序,或在不同的应用程序之间进行切换,非常方便。这些都是单任务、命令行界面的 DOS 操作系统所无法比拟的。TC2.0 或 TC3.0 均是在 DOS环境下运行的 C 系统。不过,无论采用 TC,还是 VC、BC,所产生的 C 可执行程序都是基于 DOS 系统的。C 语言发展如此迅速,而且成为最受欢迎的语言之一,主要因为它具有强大的功能。C是一种“中”级语言,它把高级语言的基本结构和语句与低级语
4、言的实用性结合起来。C 语言可以对位、字节和地址进行操作,而这三者是计算机最基本的工作单元。C 语言具有各种各样的数据类型,并引入了指针概念,可使程序效率更高。另外C 语言也具有强大的图形功能,支持多种显示器和驱动器。而且计算功能、逻辑判断功能也比较强大,可以实现决策目的。C 系统提供了大量的功能各异的标准库函数,减轻了编程的负担。所以要用C 语言实现具有类 Windows 系统应用程序界面特征的、或更生动复杂的 DOS 系统的程序,就必须掌握更高级的编程技术。这些技术与微机的硬件密切联系,除了在第一章介绍的内容外,更深入的知识将在接口和汇编这门后期课程中学习。1 文本的屏幕输出和键盘输入 问
5、题的提出编制一个程序,将屏幕垂直平分成两个窗口,左边窗口为蓝色背景,白色前景,右边窗口为绿色背景,红色前景。两个窗口都设计为文本输入,即在窗口中可以输入文字,在窗口屏幕中显示出来。使用 tab 键在左右两个窗口中切换,每个窗口都有光标,活动窗口光标进行闪烁。分析在这个问题中我们遇到了在初学 C 时不曾接触到的新概念,如文本窗口、前景色、背景色,以及围绕它们要解决的新问题:(1) 如何在屏幕中开文本输入的窗口?(2) 如何设置窗口的前景色、背景色或闪烁等显示属性?(3) 如何通过按键来控制窗口的切换?解答要解决这一编程问题,要求有两方面的学习过程:一是对于分析中的前两个问题,要求大家了解有关文本
6、的屏幕输出的知识;二是对于第 3 个问题,要求对键盘的输入有所了解。下面先就这两个方面的内容做一介绍。1.1 文本的屏幕输出显示器的屏幕显示方式有两种:文本方式和图形方式。文本方式就是显示文本的模式,它的显示单位是字符而不是图形方式下的象素,因而在屏幕上显示字符的位置坐标就用行和列表示。Turbo C 的字符屏幕函数主要包括文本窗口大小的设定、窗口颜色的设置、窗口文本的清除和输入输出等函数。这些函数的有关信息(如宏定义等)均包含在 conio.h 头文件中,因此在用户程序中使用这些函数时,必须用 include 将 conio.h 包含进程序。1)文本窗口的定义Turbo C 默认定义的文本窗
7、口为整个屏幕,共有 80 列 25 行的文本单元。如图 3-1 所示,规定整个屏幕的左上角坐标为(1,1),右下角坐标为(80,25),并规定沿水平方向为X1轴,方向朝右;沿垂直方向为 Y轴,方向朝下。每个单元包括一个字符和一个属性,字符即 ASCII 码字符,属性规定该字符的颜色和强度。除了这种默认的 80 列 25 行的文本显示方式外,还可由用户通过函数:void textmode(int newmode);来显式地设置 Turbo C 支持的 5 种文本显示方式。该函数将清除屏幕,以整个屏幕为当前窗口,并移光标到屏幕左上角。newmode 参数的取值见表 3-1,既可以用表中指出的方式代
8、码,又可以用符号常量。LASTMODE 方式指上一次设置的文本显示方式,它常用于在图形方式到文本方式的切换。(1列,1行)第一列第一行第25行图 3-1屏幕文本显示坐标表 3-1文本显示方式第80列(80列,25行)方式0123符号常量BW40C40BW80C80显示列u34892X数和颜色4025 黑白显示4025 彩色显示8025 黑白显示8025 彩色显示7 MONO-1 LASTMODE8025 单色显示上一次的显示方式Turbo C 也可以让用户根据自己的需要重新设定显示窗口,也就是说,通过使用窗口设置函数 window()定义屏幕上的一个矩形域作为窗口。window()函数的函数原
9、型为:void window(int left, int top, int right, int bottom);函数中形式参数(int left,int top)是窗口左上角的坐标,(int right,int bottom)是窗口的右下角坐标,其中(left,top)和(right,bottom)是相对于整个屏幕而言的。例如,要定义一个窗口左上角在屏幕(20,5)处,大小为 30 列 15 行的窗口可写成:window(20, 5, 50, 25);若window()函数中的坐标超过了屏幕坐标的界限,则窗口的定义就失去了意义,也就是说定义将不起作用,但程序编译链接时并不出错。窗口定义之后,
10、用有关窗口的输入输出函数就可以只在此窗口内进行操作而不超出窗口的边界。另外,一个屏幕可以定义多个窗口,但现行窗口只能有一个(因为 DOS 为单任务操作系统)。当需要用另一窗口时,可将定义该窗口的 window()函数再调用一次,此时该窗口便成为现行窗口了。2)文本窗口颜色和其它属性的设置文本窗口颜色的设置包括背景颜色的设置和字符颜色(既前景色)的设置,使用的函数及其原型为:2设置背景颜色函数:void textbackground(int color);设置字符颜色函数:void textcolor(int color);有关颜色的定义见表 3-2。表中的符号常数与相应的数值等价,二者可以互换
11、。例如设定兰色背景可以使用 textbackground(1),也可以使用 textbackground(BLUE),两者没有任何区别,只不过后者比较容易记忆,一看就知道是兰色。表 3-2 颜色表符号常数BLACKBLUEGREENCYANREDMAGENTABROWNLIGHTGRAY 7DARKGRAY 8LIGHTBLUELIGHTGREENLIGHTCYANLIGHTREDLIGHTMAGENTA YELLOWWHITE数值0123456910111213 1415含义黑蓝绿青红洋红棕淡灰深灰淡蓝淡绿淡青淡红淡洋红黄白背景或背景前景、背景色前景、背景色前景、背景色前景、背景色前景、背景
12、色前景、背景色前景、背景色前景、背景色用于前景色用于前景色用于前景色用于前景色用于前景色用于前景色用于前景色用于前景色BLINK 128闪烁用于前景色Turbo C 另外还提供了一个函数,可以同时设置文本的字符和背景颜色,这个函数是文本属性设置函数:void textattr(int attr);参数 attr 的值表示颜色形式编码的信息,每一位代表的含义如下:字节低四位 cccc 设置字符颜色,46 三位 bbb 设置背景颜色,第 7 位 B 设置字符是否闪烁。假如要设置一个兰底黄字,定义方法如下:textattr(YELLOW+(BLUE4);若再要求字符闪烁,定义变为:textattr(
13、128+YELLOW+(BLUE4);注意:(1)对于背景只有 0 到 7 共八种颜色,取大于 7 小于 15 的数,则代表的颜色与减 7 后的值对应的颜色相同;(2)用 textbackground()和 textcolor()函数设置了窗口的背景与字符颜色后,在没有用 clrscr()函数清除窗口之前,颜色不会改变,直到使用了函数 clrscr(),整个窗口和随后输出到窗口中的文本字符才会变成新颜色。3(3)用 textattr()函数时背景颜色应左移 4 位,才能使 3 位背景颜色移到正确位置;例程 3-1:这个程序使用了关于窗口大小的定义、颜色的设置等函数,在一个屏幕上不同位置定义了
14、7 个窗口,其背景色分别使用了 7 种不同的颜色。/*-例程 3-1-*/#include #include int main()int i; textbackground(0); /*设置屏幕背景色,待 clrscr 后起作用 */clrscr();for(i=1; i8; i+)/*清除文本屏幕 */window(10+i*5, 5+i, 30+i*5, 15+i); /*定义文本窗口 */textbackground(i);clrscr();/*定义窗口背景色 */*清除窗口 */getch();return 0; void highvideo(void);该函数将设置用高亮度显示字符。
15、void lowvideo(void);该函数将设置用低亮度显示字符。void normvideo(void);该函数将设置通常亮度显示字符。3)窗口内文本的输入输出函数窗口内文本的输出函数我们以前介绍过的 printf(),putc(),puts(),putchar()和输出函数以整个屏幕为窗口的,它们不受由 window 设置的窗口限制,也无法用函数控制它们输出的位置,但 Turbo C 提供了三个文本输出函数,它们受窗口的控制,窗口内显示光标的位置,就是它开始输出的位置。当输出行右边超过窗口右边界时,自动移到窗口内的下一行开始输出,当输出到窗口底部边界时,窗口内的内容将自动产生上卷,直到
16、完全输出完为止,这三个函数均受当前光标的控制,每输出一个字符光标后移一个字符位置。这三个输出函数原型为:int cprintf(char *format,表达式表);int cputs(char *str);int putch(int ch);它们的使用格式同 printf(),puts()和 putc(),其中 cprintf()是将按格式化串定义的字符串或数据输出到定义的窗口中,其输出格式串同 printf 函数,不过它的输出受当前光标控制,且输出特点如上所述,cputs 同 puts,是在定义的窗口中输出一个字符串,而 putch()则是输出一个字符到窗口,它实际上是函数 putc 的一
17、个宏定义,即将输出定向到屏幕。窗口内文本的输入函数4可直接使用 stdio.h 中的 getch 或 getche 函数。需要说明的是,getche()函数从键盘上获得一个字,在屏幕上显示的时候,如果字符超过了窗口右边界,则会被自动转移到下一行的开始位置。4)有关屏幕操作的函数 void clrscr(void);该函数将清除窗口中的文本,并将光标移到当前窗口的左上角,即(1, 1)处。 void clreol(void);该函数将清除当前窗口中从光标位置开始到本行结尾的所有字符,但不改变光标原来的位置。 void delline(void);该函数将删除一行字符,该行是光标所在行。void
18、gotoxy(int x, int y);该函数很有用,用来定位光标在当前窗口中的位置。这里 x,y 是指光标要定位处的坐标(相对于窗口而言)。当 x, y 超出了窗口的大小时,该函数就不起作用了。int movetext(int x1, int y1, int x2, int y2, int x3, int y3);该函数将把屏幕上左上角为(xl,y1),右下角为(x2,y2)的矩形内文本拷贝到左上角为(x3,y3)的一个新矩形区内。这里 x,y 坐标是以整个屏幕为窗口坐标系,即屏幕左上角为(1,1)。该函数与开设的窗口无关,且原矩形区文本不变。int gettext(int xl, int
19、 yl, int x2, int y2, void *buffer);该函数将把左上角为(xl,y1),右下角为(x2,y2)的屏幕矩形区内的文本存到由指针 buffer指向的一个内存缓冲区内,当操作成功,返回 1;否则,返回 0。因一个在屏幕上显示的字符需占显示存储器 VRAM 的两个字节,即第一个字节是该字符的ASCII码,第二个字节为属性字节,即表示其显示的前景、背景色及是否闪烁,所以buffer 指向的内存缓冲区的字节总数的计算为:字节总数=矩形内行数u27599X行列数2其中:矩形内行数=y2-y1+l,每行列数=x2-xl+1(每行列数是指矩形内每行的列数)。矩形内文本字符在缓冲区
20、内存放的次序是从左到右,从上到下,每个字符占连续两个字节并依次存放。int puttext(int x1, int y1, int x2, int y2, void *buffer);该函数则是将 gettext()函数存入内存 buffer 中的文字内容拷贝到屏幕上指定的位置。注意:(1) gettext()函数和puttext()函数中的坐标是对整个屏幕而言的,即是屏幕的绝对坐标,而不是相对窗口的坐标;(2) movetext()函数是拷贝而不是移动窗口区域内容,即使用该函数后,原位置区域的文本内容仍然存在。例程 3-2:下面的程序首先定义了一个字符数组,下标为 64,表示用来存四行八列的
21、文本。由于没有用 window 函数设置窗口,因而用缺省值,即全屏幕为一个窗口,程序开始设置 80列25 行文本显示方式(C80),背景色为蓝色,前景色为红色,经 clrscr 函数清屏后,设置的背景色才使屏幕背景变蓝。gotoxy(10,10)使光标移到第 10 行 10 列,然后在(10,10)开始位置显示 L:load,接着在下面三行相同的列位置显示另外三条信息,13 行 10 列显示的E:exit后面带有回车换行符,为的是将光标移到下一行开始处,好显示press any key to continue。当按任一键后,gettext 函数将(10,l0,18,13)矩形区的内容存到 ch
22、 缓存区内。ch 即上述的四行八列信息,接着设置一个窗口,并纵向写上 1,2,3,4,然后用 movetext(),5将此窗口内容复制到另一区域,由于此区域包括背景色和显示的字符,所以被复制到另一区域的内容也是相同的背景色和文本。当按任一键后,又出现提示信息,再按键,则存在ch缓冲区内的文本由 puttext()又复制到开设的窗口内了,注意上述的函数 movetext(),gettext(),puttext()均与开设的窗口内坐标无关,而是以整个屏幕为参考系的。 /*-例程 3-2-*/#include main()int i;char ch4*8*2;textmode(C80);/*定义 c
23、h 字符串数组作为缓存区 */textbackground(BLUE);textcolor(RED);clrscr();gotoxy(10,10);cprintf(L:load);gotoxy(10,11);cprintf(S:save);gotoxy(10,12);cprintf(D:delete);gotoxy(10,13);cprintf(E:exitrn);cprintf(Press any key to continue);getch();gettext(10,10,18,13,ch); /*存矩形区文存到 ch 缓存区 */clrscr();textbackground(1);te
24、xtcolor(3);window(20,9,34,14);clrscr();/*开一个窗口 */cprintf(1.r n2.rn3.rn4.rn);/* 纵向写 1,2,3,4*/movetext(20,9,34,14,40,10); /*将矩形区文本复制到另一区域 */puts(hit any key);getch();clrscr();cprintf(press any key to put text);getch();clrscr();puttext(23,10,31,13,ch); /*将 ch 缓存区所存文本在屏上显示*/getch();5)状态查询函数有时需要知道当前屏幕的显示
25、方式,当前窗口的坐标、当前光标的位置,文本的显示6属性等,Turbo C 提供了一些函数得到屏幕文本显示有关信息的函数:void gettextinfo(struct text_info *f);这里的 text_info 是在 conio.h 头文件中定义的一个结构,该结构的定义是Struct text_info( unsigned char winleft; unsigned char wintop; unsigned char winright; unsigned char winbottom; /* 窗口左上角 x 坐标*/* 窗口左上角 y 坐标*/*窗口右下角 x 坐标*/*窗口右
26、下角 y 坐标*/unsigned char attribute;unsigned char normattr; unsigned char currmode;unsigned char screenheight;/*文本属性/*通常属性/*当前文本方式/*屏高*/ */ */ */ unsigned char screenwidth; /* 屏宽*/ ;unsigned char curx;unsigned char cury; /* 当前光标的 x 值/* 当前光标的 y 值*/*/例程 3-3:下面的程序将屏幕设置成 80 列彩色文本方式,并开了一个 window(1,5,70,20)的
27、窗口,在窗口中显示了 current information of window,然后用 gettextinfo 函数得到当前窗口的信息,后面的 cprintf()函数将分别显示出结构 text_info 各分量的数值来,即:current information of window Left corner of window is l,5 Right corner of window is 70,20 Text window attributeis 29 Text window normal attribute is 29 Current video mode is 3 window hei
28、ght andwidth is 25,80 Row cursor pos is 2,Column pos is 1/*-例程 3-3-*/#include main() struct text_info current; textmode(C80); textbackground(1); textcolor(13); window(1,5,70,20); clrscr(); cputs(Current information of windowrn); gettextinfo(¤t); cprintf(Left corner of window is %d,%d,current.w
29、inleft,current.wintop); cprintf(Right corner of window is %d,%d,current.winright,current.winbottom); cprintf(Text window attribute is%d, current.attribute); cprintf(Text window normal attribute,current.normattr);7 cprintf(Current video mode is%d,current.currmode); cprintf(Window height and width is%
30、d,%d, current.screenheight,current.screenwidth); cprintf(Row cursor pos is %d,Column pos is %d, current.cury,current.curx); getch();1.2 键盘输入当我们按下键盘上某键时,系统如何知道某键被按下呢?它的奥妙在于计算机键盘是一个智能化的键盘,在键盘内有一个微处理器,它用来扫描和检测每个键的按下和拾起状态。然后以程序中断的方式(INT 9)与主机通信。ROM 中 BIOS 内的键盘中断处理程序,会将一个字节的按键扫描码(扫描码的 06 位标识了每个键在键盘上的位置,最
31、高位标识按键的状态,0对应该键是被按下;1对应松开。它并不能区别大小写字母,而且一些特殊键如PrintScreen 等不产生扫描码直接引起中断调用)翻译成对应的 ASCII 码。由于 ASCII 码仅有 256 个(28),它不能将 PC 键盘上的键全部包括,因此有些控制键如CTRL,ALT,END,HOME,DEL 等用扩充的 ASCII 码表示,扩充码用两个字节的数表示。第一个字节是 0,第二个字节是 0255 的数,键盘中断处理程序将把转换后的扩充码存放在Ax 寄存器中,存放格式如表 3-3 所示。对字符键,其扩充码就是其 ASCII 码。表 3-3键盘扫描码键名AHAL字符键扩充码=ASCII 码ASCII 码功能键/组合键扩充码0是否有键按下,何键按下,简单的应用中可采用两种办法:一是直接使用 Turbo C 提供的键盘操作函数 bioskey()来识别,二是通过第一章 1.2.4.3 节介绍的 int86()函数,调用 BIOS的 INT 16H,功能号为 0 的中断。它将按键的扫描码存放在 Ax 寄存器的高字节中。函数 bioskey()的原型为:int bioskey(int cmd);