在本章,我们就课程设计中涉及的一些知识点作一个概述。这些知识点主要包括图形
基础与图形函数、文件操作知识、动画技术、中断知识和发声技术等,是在TurboC 下的操
作方式,不适用于VC++。

3.图形知识
1 

C语言中提供了丰富的图形处理函数,本节将对本书中涉及的图形知识点作一个简要
回顾,主要包括图形模式的初始化、屏幕设置函数、颜色相关函数、画图函数、填充函数、文本
输出函数,以及与这些函数相关的各项参数等。

3.1 
图形模式的初始化
1.
1.voidfarinitgrapintfar*gdriveintfar*gmodchar*pat
h(r,e,h) 

功能:显示模式控制。gdriver和gmode分别表示图形驱动器和模式,path是指图形驱
动程序所在的目录路径。有关图形驱动器、图形模式及分辨率的值如表3.

1所示。

表3.1 
图形驱动器、图形模式及分辨率参照表

图形驱动器(gdriver) 图形模式(gmode) 色调分辨率
符号常数数值符号常数数值
CGAC0 0 C0 320×200 
CGAC1 1 C1 320×200 
CGA 1 CGAC2 2 C2 320×200 
CGAC3 3 C3 320×200 
CGAHI 4 2色640×200 
MCGAC0 0 C0 320×200 
MCGA 2 MCGAC1 1 C1 320×200 
MCGAC2 2 C2 320×200 
MCGAC3 3 C3 320×200 


续表

图形驱动器(gdriver) 图形模式(gmode) 色调分辨率
符号常数数值符号常数数值
MCGA 2 MCGAMED 4 2色640×200 
MCGAHI 5 2色640×480 
EGA 3 EGALO 0 16 色640×200 
EGAHI 1 16 色640×350 
EGA64 4 EGA64LO 0 16 色640×200 
EGA64HI 1 4色640×350 
EGAMON 5 EGAMONHI 0 2色640×350 
IBM8514 6 IBM8514LO 0 256 色640×480 
IBM8514HI 1 256 色1024×768 
HERC 7 HERCMONOHI 0 2色720×348 
PC3270 10 PC3270HI 0 2色720×350 
DETECT 0 用于硬件测试
ATT400C0 0 C0 320×200 
ATT400C1 1 C1 320×200 
ATT400 8 ATT400C2 2 C2 320×200 
ATT400C3 3 C3 320×200 
ATT400MED 4 2色320×200 
ATT400HI 5 2色320×200 
VGAL0 0 16 色640×200 
VGA 9 VGAMED 1 16 色640×350 
VGAHI 2 16 色640×480 

h(r,e)

2.voidfardetectgrapint*gdrive*gmod

功能:自动检测显示器硬件。gdriver和gmode与initgraph() 函数中的意义一样,仍然
分别表示图形驱动器和模式。

3.2 
屏幕颜色相关函数
1.
r(r)
1.voidfarsetbkcolointcolo

功能:设置背景色。其中,r表示作图的颜色,可以用颜色的符号常量表示,也可以

colo
用代表该颜色的数值来表示,颜色符号常量和对应数值的关系如表3.

2所示。


47 
表3.2 颜色符号常量与其数值对应表
符号常量数 值含 义符号常量数 值含 义
BLACK 0 黑色DARKGRAY 8 深灰色
BLUE 1 蓝色LIGHTBLUE 9 淡蓝色
GREEN 2 绿色LIGHTGREEN 10 淡绿色
CYAN 3 青色LIGHTCYAN 11 淡青色
RED 4 红色LIGHTRED 12 淡红色
MAGENTA 5 洋红色LIGHTMAGENTA 13 淡洋红色
BROWN 6 棕色YELLOW 14 黄色
LIGHTGRAY 7 淡灰色WHITE 15 白色
2.voidfarsetcolor(intcolor) 
功能:设置前景色,color的取值参见表3.2。
3.intfargetbkcolor(void) 
功能:返回当前背景色。
4.intfargetcolor(void) 
功能:返回当前背景色。
5.intfargetmaxcolor(void) 
功能:返回当前可用的最大颜色值。
3.1.3 图形窗口和图形屏幕函数
1.图形窗口操作 
1)voidfarsetviewport(intx0,inty0,intx1,inty1,intclipflag) 
设定一个以(x0,y0)为左上角、以(x1,y1)为右下角的图形窗口,其中,x0、y0、x1、y1是
相对于整个屏幕的坐标。如果clipflag为1,则超出窗口的输出图形自动被裁剪掉,即所有
作图限制于当前图形窗口之内;如果clipflag为0,则不进行裁剪,即作图将无限制地扩展于
窗口边界之外,直到屏幕边界。
2)voidfarclearviewport(void) 
清除当前图形窗口,并把光标从当前位置移到原点(0,0)。
3)voidfargetviewsettings(structviewporttypefar*viewport) 
获得关于现行窗口的信息,并将其存于viewporttype定义的结构变量viewport中。其
中,viewporttype的结构说明如下: 
struct viewporttype

48 
{ 
int left,top,right,bottom; 
int clipflag; 
}; 
2.图形屏幕操作
1)voidfarsetactivepage(intpagenum) 
为图形输出选择激活页,即后续图形的输出被写到函数选定的pagenum 页面,该页面
并不一定可见。
2)voidfarsetvisualpage(intpagenum) 
使pagenum 所指定的页面变成可见页,页面从0开始。如果先用setactivepage()函数
在不同页面上画出一幅幅图像,再用setvisualpage()函数交替显示,就可以实现一些动画的
效果。
3)unsinedfarimagesize(intx0,inty0,intx1,inty1) 
该函数一般在保存指定范围内的像素时使用,它计算要保存从左上角为(x0,y0)到右
下角为(x1,y1)的图形屏幕区域所需的字节数。
4)voidfargetimage(intx0,inty0,intx1,inty1,voidfar*buf) 
将从左上角为(x0,y0)到右下角为(x1,y1)的图形屏幕区域的图像保存到buf所指向
的内存空间,该内存空间的大小由imagesize()函数计算。
5)voidfarputimage(intx,inty,void* mapbuf,intop) 
将保存的图像输出到左上角点(x,y)的位置上,op规定了如何释放内存中的图像,图像
输出方式如表3.3所示。
表3.3 图像输出方式
符号常数数值含 义符号常数数值含 义
COPY_PUT 0 复制AND_PUT 3 与屏幕图像与后复制
XOR_PUT 1 与屏幕图像异或的复制NOT_PUT 4 复制反像的图形
OR_PUT 2 与屏幕图像或后复制 
6)voidfarcleardevice(void) 
清除屏幕内容。
3.1.4 画图函数
1.画点 
1)画点函数
(1)voidfarputpixel(intx,inty,intcolor) 
在坐标(x,y)处以color所代表的颜色画一点。
(2)intfargetpixel(intx,inty) 
获得点(x,y)处的颜色值。

2)有关坐标位置的函数

(1)intfargetmaxx(void)
返回x轴的最大值
。
(2)intfargetmaxy(void)
返回y轴的最大值
。
(3)intfargetx(void)


返回光标所在位置的横坐标。

(4)voidfargety(void)
返回光标所在位置的纵坐标
。
(5)viavtitx,
n


odfrmoeo(nity)
移动光标到(x,y)点
。
(6)vl(x,


oidfarmovereintdintdy)
把光标从当前位置(x,y)移动到位置(x+dx,y+dy)
。


2.画线
1)画线函数

(1)viaie(n0,nitxity1)

odfrlnitxity0,n1,
n
从点(x0,y0)到点(x1,y1)画直线
。
(2)vdfrlnto(nity)


oiaieitx,
n
画一条从当前位置到(x,y)的直线
。
(3)vodfrlnrl(nx,
n


iaieeitditdy)
画一条从当前位置(x,y)到位置(x+dx,y+dy)之间的直线
。
(4)viaice(nititrdu


odfrcrlitx,ny,nais)
以(x,y)为圆心、radius为半径画一个圆
。
(5)viaritx,nitsaglitednge,nais)


odfrac(nity,ntne,nnalitrdu
以(x,y)为圆心、radius为半径,画一段从stangle(角度)到endangle(角度)的圆弧线。
6)vodepitx,nitsagitednlnrdunrdu

(e(e,e,s,s)

以(x,y)为中心,以xradius、yradius分别为x轴和y轴半径,画一段从角stangle到

endangle的椭圆线
odfrr
。
ca
当
gstean(
gnle=
10,
、
nendangiletx=360 
it
时,画出一个完整的椭圆。
(7)viaetnlitxity1,n2,ny2)
以(x1,y1)为左上角、(x2,y2)为右下角画一个矩形框。
oidfardrawpolintnumpointintfar*polypoint

ilisnity,ntnlnnagitxaiityai

(8)vy(s,s)
画一个顶点数为numpoints、各顶点坐标由polypoints给出的多边形
。
2)设定线型函
数
(1)vodfrstietlitlnsye,nindupten,nhcns)


iaelnsye(nietlusgearittike
该函数用来设置线的有关信息,其中linestyle表示线的形状(线形状的取值及含义见
表3.4),tike表示线的宽度( 5),对于uar

hcns 
线宽度的取值及含义见表3.pten,只有
linestyle选USERBITLINE时才有意义(选其他线型,upatern取0即可)。此处upatern 
的16位二进制数的每一位代表一个像元,如果为1,则该像元打开,否则该像元关闭。


表3.线形状的取值及含义

4 

符号常数数值含义符号常数数值含义
SOLID_LINE 0 实线DASHED_LINE 3 点画线
DOTTED_LINE 1 点线USERBIT_LINE 4 用户定义线
CENTER_LINE 2 中心线

表3.线宽的取值及含义

5 

符号常数数值含义
NORM_WIDTH 1 一点宽
THIC_WIDTH 3 三点宽

(2)viarsewriemoe(nd

odfttditmoe) 

该函数规定画线的方式。mode的取值为1或0。当取0时,表示画线时将所画位置的
原来信息覆盖了;当取1时,则表示画线时用现在特性的线与所画之处原有的线进行异或
(XOR)操作,实际上画出的线是原有线与现在规定的线进行异或后的结果。因此,当线的
特性不变,进行两次画线操作相当于没有画线。

3.5 
封闭图形的填充
1.
1.先画轮廓再填充
1)vodfrbr(ntx1,nty1,itxity2)

iaaiin2,n
先画一个以(y1,y1)为左上角、(x2,y2)为右下角的矩形窗口,再按规定模式和颜色
填充。
2)vodfrbritxity0,n1,nitdph,nofa

iaa3d(n0,nitxity1,netittplg) 
当topflag为非0时,画出一个三维的长方体;当topflag为0时,三维图形不封顶。
3)vodfrpelcitx,nitsage,nnage,nais)

iaisie(nity,ntnlitednlitrdu
先画一个以(x,y)为圆心、radius为半径、从角度stangle到角度endangle的扇形,再按
规定方式填充。
4)vodfrscoitx,nitsage,nednlitxais,nrdu

iaetr(nity,ntnlitnage,nrduityais) 
先画一个以(x,y)为圆心,以xradius、yradius分别为x轴和y轴半径,从角度stangle 
到角度endangle的椭圆扇形,再按规定方式填充。

2.任意封闭图形的填充
vodfrfodiitx,nitbre:该函数可对任意封闭图形进行填充。其中

ialofl(nity,nodr)
(x,y)为封闭图形内的任意一点,border为边界的颜色,border指定的颜色值必须与图形轮
廓的颜色值相同。

提示:(x,y)必须在所要填充的封闭图形内部,否则不能进行填充。如果不是封闭图
形,则填充会从没有封闭的地方溢出去,填满其他地方。


51 
3.设定填充方式
1)voidfarsetfillstyle(intpattern,intcolor) 
以pattern为填充模式和以color为填充颜色对指定图形进行填充。填充模式pattern 
的取值和含义如表3.6所示。
表3.6 填充模式pattern的取值和含义
符号常数数值含 义符号常数数值含 义
EMPTY_FILL 0 以背景色填充HATCH_FILL 7 直线网格填充
SOLID_FILL 1 实填充XHATCH_FILL 8 斜网格填充
LINE_FILL 2 直线填充INTTERLEAVE_FILL 9 间隔点填充
LTSLASH_FILL 3 斜线填充WIDE_DOT_FILL 10 稀疏点填充
SLASH_FILL 4 粗斜线填充CLOSE_DOS_FILL 11 密集点填充
BKSLASH_FILL 5 粗反斜线填充USER_FILL 12 用户自定义填充
LTBKSKASH_FILL 6 反斜线填充 
2)voidfarsetfillpattern(char* upattern,intcolor) 
该函数用于设置用户定义的填充图形的颜色,以供对封闭图形进行填充。其中, 
upattern是一个指向8字节的指针。这8字节定义了8×8点阵的图形。每字节的8 位二
进制数表示水平8点,8字节表示8行,然后以此为模型向各封闭区域填充。
3)voidfargetfillpattern(char* upattern) 
该函数将用户定义的填充图模存入upattern指针指向的内存区域。
4)voidfargetfillsetings(structfillsettingstypefar*fillinfo) 
获得当前图形模式的颜色并将其存入结构指针变量fillinfo中。其中,fillsettingstype 
结构定义如下: 
struct fillsettingstype 
{ 
int pattern; 
int color; 
}; 
其中,pattern表示当前的填充模式,color表示填充的颜色。
3.1.6 图形模式下的文本输出
1.文本输出函数 
1)voidfarouttext(charfar*text) 
该函数输出字符串指针text所指的文本所在的位置。
2)voidfarouttextxy(intx,inty,charfar*text) 
该函数在指定位置(x,y)输出字符串指针text所指的文本。

2.文本参数设置函数
1)vodfrstooitclr)

iaeclr(noo
该函数用于设置输出文本的颜色,color表示要设置的颜色
。
2)vy(z,t)


oidfarsetextjustifinthoriintver
该函数用于设置显示的方位。对使用outextxy()函数所输出的字符串,其中,哪个点
对应于坐标(在Tu0中是有规定的。如果把一个字符串看成一个长方形的图

x,y) rboC2.
形,在水平方向显示时,字符串长方形在垂直方向就有顶部、中部和底部三个位置,水平方向
就有左、中、右三个位置,两者结合所确定的位置就对准函数中的(x,y)位置。

setextjustify()函数中的参数horiz指出水平方向的位置(即左、中、右中的一个),参数
vert指出垂直方向的位置(即顶部、中部、底部中的一个)。有关参数horiz和vert的取值及
含义见表3.

7。

表3.7 
参数horiz和vert的取值及含义

符号常数数值含义符号常数数值含义
LEFT_TEXT 0 水平TOP_TEXT 2 垂直
RIGHT_TEXT 2 水平CENTER_TEXT 1 水平或垂直
BOTTOM_TEXT 0 垂直

e(t,n,e)
该函数用于设置输出字符的字体font(见表3.方向directioharsize 

3)voidfarsetextstylintfonintdirectiointcharsiz

8)、n和字体大小c(见表3.9)。其中方向direction的取值有HORIZ_DIR(用数值0表示)和VERT_DIR(用
数值1表示)两个,分别表示从左向右和从底向顶输出字符。

表3.字体ft的取值及含义

8 
on

符号常数数值含义
DEFAULT_FONT 0 默认字体,8×8点阵字体
TRIPLEX_FONT 1 三倍笔画字体
SMALL_FONT 2 小号笔画字体
SANSSERIF_FONT 3 无衬线笔画字体
GOTHIC_FONT 4 黑体笔画字体

表3.字体大小ce的取值及含义

9 
harsiz

符号常数或数值含义
1 8×8点阵
2 16×16点阵
3 24×24点阵
4 32×32点阵


53 
续表
符号常数或数值含 义
5 40×40点阵
6 48×48点阵
7 56×56点阵
8 64×64点阵
9 72×72点阵
10 80×80点阵
USER_CHAR_SIZE=0 用户定义的字符大小
3.2 文件操作知识 
本节我们将对文件操作的基本知识作一个简要回顾,包括文件的打开与关闭、文件的读
写、文件的状态判断及文件的定位。
3.2.1 文件的打开与关闭
1.文件的打开 
C语言中打开文件的函数是fopen(),其一般调用形式如下: 
FILE *fp 
fp=fopen(filename, method) 
其中,fp是一个指向FILE 类型结构体的指针变量,filename表示要打开的文件的名
字,method表示文件的使用方式,表3.10列出了文件的使用方式及其含义。
表3.10 文件的使用方式及其含义
文件的使用方式含 义文件的使用方式含 义
r,只读为输入打开一个文本文件r+,读写为读/写打开一个文本文件
w,只写为输出打开一个文本文件w+,读写为读/写建立一个新的文本文件
a,追加向文本文件尾增加数据a+,读写为读/写打开一个文本文件
rb,只读为输入打开一个二进制文件rb+,读写为读/写打开一个二进制文件
wb,只写为输出打开一个二进制文件wb+,读写为读/写建立一个新的二进制文件
ab,追加向二进制文件尾增加数据ab+,读写为读/写打开一个二进制文件 
提示:如果不能打开一个文件,即打开文件失败,则fopen()函数将返回一个空指针
NULL。通常可以通过判断fopen()返回的值来决定是否打开成功。

54 
2.文件的关闭
在使用完一个文件后应该关闭它,以防止它被误用。关闭文件的函数是fclose(),其一
般调用形式如下: 
fclose(fp) 
fp即为文件指针,是我们前面打开文件时创建的fp。fclose()函数也有返回值,如果顺
利关闭的话则返回0;否则返回-1,可以用ferror()函数(见3.2.3节)来测试。
3.2.2 文件的读写
对文件的读写,可以有多种方式,可以读写一个字符、一个字符串、一块数据或者一个整
数,有时候也需要进行格式化输入和输出等。
1.从文件读出
1)fgetc() 
fgetc()函数用于从一个指定的文件中读出一个字符,该文件必须是以读或者读写方式
打开的,其一般调用形式如下: 
ch=fgetc(fp) 
fp为文件型指针变量,ch为读出的字符变量。
2)fgets() 
fgets()函数用于从一个指定的文件中读出一个字符串,其一般调用形式如下: 
fgets(str, num, fp) 
num 为需要读取的字符个数,fp为文件型指针变量。从fp指向的文件中读取num-1 
个字符,然后在最后加一个\' 0'字符,再把它们放入数组str中。
3)getw() 
getw()函数表示从一个磁盘文件中读取一个整数,其一般调用形式如下: 
getw(fp) 
fp为文件型指针变量。
4)fread() 
fread()函数用于读取一组数据,其一般调用形式如下: 
fread(buffer, size, count, fp) 
buffer是读取数据所存放的地方,size表示要读写的字节数,count表示要进行读写多
少字节的数据项,fp为文件型指针。
5)fscanf() 
fscanf()函数用于从磁盘文件中读取ASCII字符,并将读取的数据存入指定变量中,其
一般调用形式如下:

55 
fscanf(fp, format string, in_list) 
fp为文件型指针,formatstring是格式字符串,in_list表示输入表列。
2.写入文件
1)fputc() 
fputc()函数表示将一个字符写入指定的磁盘文件中,其一般调用形式如下: 
fputc(ch, fp) 
ch为要写入的字符,fp为文件型指针变量。
2)fputs() 
fputs()函数表示向指定文件写入一个字符串,其一般调用形式如下: 
fputs(str, fp) 
str表示要写入的字符串,fp为文件型指针变量。
3)putw() 
putw()函数用于将一个整数写入指定的文件,其一般调用形式如下: 
putw(digit, fp) 
digit表示要写入的整数,fp为文件型指针变量。
4)fwrite() 
fwrite()用来将一组数据写入指定的文件,其一般调用形式如下: 
fwrite(buffer, size, count, fp) 
其各个参数的意义和fread()函数中的相同,只是这里的buffer存放的是要写入文件的
数据。
5)fprintf() 
fprintf()函数用于格式化输出字符串到指定的文件,其一般调用形式如下: 
fprintf(fp, format string, out_list) 
fp为文件型指针,formatstring是格式字符串,out_list表示输出表列。我们举例来说
明如下: 
fprintf(fp,"%d, %2.2f", i, j) 
本语句的作用是将整型变量i和实型变量j的值按照%d和%2.2f的形式输出到fp所
指向的文件上。
3.2.3 文件的状态
1.文件结束判断 
在ANSI标准中,使用feof()函数来判断文件是否结束,其一般调用形式如下:

56 
feof(fp) 
fp为文件型指针,如果遇到文件结束符,即表示文件结束返回非0,否则返回0。
2.错误检测及清除
1)ferror() 
在调用各种输入输出函数时,如果出现了错误,可以用ferror()函数来检测,其一般调
用形式如下: 
ferror(fp) 
如果ferror返回0,则表示没有出错。
2)clearer() 
clearer()函数用于将文件错误标志和文件结束标志置为0,其一般调用形式如下: 
clearer(fp) 
如果在调用一个输入输出函数出错后,再调用该函数,即可将ferror()值清为0。
3.2.4 文件的定位
文件中有一个位置指针指向当前读写的位置。有时我们需要获取位置指针的位置或者
改变当前的指向位置,C语言中提供了几个函数来实现这些功能。
1.rewind() 
rewind()函数将位置指针重新返回到文件的开头,其一般调用形式如下: 
rewind(fp) 
2.ftell() 
ftell()函数用于获取流式文件中的当前位置,用相对于文件开头的位移量来表示,其一
般调用形式如下: 
ftell(fp) 
如果返回正整数,则表示当前的存放位置,如果返回值为-1L,则表示出错。
3.fseek() 
fseek()函数用于实现改变位置指针所指向的位置,其一般调用形式如下: 
(文件类型指针,位移量,起始点) 
起始点有三个值,分别是文件开始(SEEK_SET,用数字0表示)、文件当前位置(SEEK 
_CUR,用数字1表示)和文件末尾(SEEK_END,用数字2表示);位移量是以起始点为基点
而移动的字节数,如果字节数为正表示向前移动,如果为负则表示向后移动。ANSIC标准
要求位移量是long型数据,并规定在数字的末尾加一个字母L,表示long型。

57 
举例说明,假定有如下的调用: 
fseek(fp, 100L, 1) 
该语句表示将位置指针向前移动到离当前位置100字节处。
3.3 动画技术 
我们知道电影或动画片是由一张张图像组成的,它利用人眼不能够分辨出时间间隔在
25毫秒内的动态图像变化这一特性,在这些连续图像被放映时,从视觉效果上给人以动的
感觉。所以在计算机屏幕上产生运动的效果需要动画技术。
3.3.1 采用延迟与清屏交错的实现方法
这种方法利用cleardevice()和delay()函数相互配合,先画一幅图形,让它延迟一段时
间,然后清屏,再画另一幅,如此反复,就形成动态效果。本小节的例3-1分别通过函数
graphone()、graphtwo()和graphthree()实现了三幅简单的动画画面,这三幅画面不停地进
行切换。
例3-1 
#include<graphics.h> 
#include<stdlib.h> 
#include<dos.h> 
int x,y,maxcolor; 
void graphone(char *str); /*使字符串str 左右运动,线条上下运动*/ 
void graphtwo(char *str); /*使字符串str 上下运动,线条左右运动*/ 
void graphthree(char *str); /*使字符串str 由小变大,再由大变小,直线也随之变化*/ 
main() 
{ 
int i,driver,mode; 
char *str="W E L C O M E !"; 
driver=DETECT; 
mode=0; 
initgraph(&driver,&mode,""); /*系统初始化*/ 
cleardevice(); /*清屏*/ 
settextjustify(CENTER_TEXT,CENTER_TEXT); 
x=getmaxx(); /*返回当前图形模式下的最大有效的x 值*/ 
y=getmaxy(); /*返回当前图形模式下的最大有效的y 值*/ 
maxcolor=getmaxcolor(); /*返回当前图形模式下最大有效的颜色值*/ 
while(!kbhit()) 
{ 
graphone(str); /*第一个动画*/ 
graphtwo(str); /*第二个动画*/ 
graphthree(str); /*第三个动画*/ 
}

58 
getch(); 
closegraph(); /*关闭图形模式*/ 
}v
oid graphone(char *str) 
{ 
int i; 
for(i=0;i<40;i++) 
{ 
setcolor(1); 
settextstyle(1,0,4); 
setlinestyle(0,0,3); 
cleardevice(); 
line(150,y-i*15,150,y-300-i*15); 
line(170,y-i*15-50,170,y-350-i*15); 
line(130,y-i*15-50,170,y-i*15-50); 
line(150,y-300-i*15,190,y-300-i*15); 
line(x-150,i*15,x-150,300+i*15); 
line(x-170,i*15-50,x-170,250+i*15); 
line(x-150,i*15,x-190,i*15); 
line(x-130,250+i*15,x-170,250+i*15); 
outtextxy(i*25,150,str); 
outtextxy(x-i*25,y-150,str); 
delay(5000); 
} 
}v
oid graphtwo(char *str) 
{ 
int i; 
for(i=0;i<30;i++) 
{ 
setcolor(5); 
cleardevice(); 
settextstyle(1,1,4); 
line(i*25,y-100,300+i*25,y-100); 
line(i*25,y-120,300+i*25,y-120); 
line(x-i*25,100,x-300-i*25,100); 
line(x-i*25,120,x-300-i*25,120); 
outtextxy(150,i*25,str); 
outtextxy(x-150,y-i*25,str); 
delay(5000); 
} 
}v
oid graphthree(char *str) 
{ 
int i,j,color,width;

59 
color=random(maxcolor); /*随机得到颜色值*/ 
setcolor(color); 
settextstyle(1,0,1); /*设置字符串的格式*/ 
outtextxy(x/2,y/2-100,str); /*显示字符串*/ 
delay(8000); 
for(i=0;i<8;i++) /*字符串由小变大*/ 
{ 
cleardevice(); /*清屏*/ 
settextstyle(1,0,i); 
outtextxy(x/2,y/2-i*10-100,str); 
outtextxy(x/2,y/2+i*10-100,str); 
width=textwidth(str); /*得到当前字符串宽度*/ 
setlinestyle(0,0,1); /*设置画线格式*/ 
line((x-width)/2+10*(8-i),y/2+ i*15- 70,(x+ width)/2- 10*(8- i),y/2+ i* 
15-70); 
line((x-width)/2+5*(8-i),y/2+i*15-60,(x+width)/2-5*(8-i),y/2+i* 
15-60); 
line((x-width)/2,y/2+i*15-50,(x+width)/2,y/2+i*15-50); 
line((x-width)/2,y/2+i*15-20,(x+width)/2,y/2+i*15-20); 
line((x-width)/2+5*(8-i)-10,y/2+i*15-10,(x+width)/2-5*(8-i),y/2+ 
i*15-10) 
line((x-width)/2+10*(8-i),y/2+i*15,(x+width)/2-10*(8-i),y/2+i*15); 
delay(8000); 
} 
for(i=7;i>=0;i--) /*字符串由大变小*/ 
{ 
cleardevice(); /*清屏*/ 
settextstyle(1,0,i); 
outtextxy(x/2,y/2-i*10-100,str); 
outtextxy(x/2,y/2+i*10-100,str); 
width=textwidth(str); 
setlinestyle(0,0,1); 
line((x-width)/2+10*(8-i),y/2+ i*15- 70,(x+ width)/2- 10*(8- i),y/2+ i* 
15-70); 
line((x-width)/2+5*(8-i),y/2+i*15-60,(x+width)/2-5*(8-i),y/2+i* 
15-60); 
line((x-width)/2,y/2+i*15-50,(x+width)/2,y/2+i*15-50); 
line((x-width)/2,y/2+i*15-20,(x+width)/2,y/2+i*15-20); 
line((x-width)/2+5*(8-i),y/2+i*15-10,(x+width)/2-5*(8-i),y/2+i* 
15-10); 
line((x-width)/2+10*(8-i),y/2+i*15,(x+width)/2-10*(8-i),y/2+i*15); 
delay(8000); 
} 
}
程序中用到的库有graphics.h、dos.h和stdlib.h。其中,graphics.h 中的图形函数,除

60 
initgraph()、cleardevice()、closegraph()、settextjustify()、settextstyle()、setlinestyle()、
outtextxy()、setcolor()、line()外,还包括如下: 
void far textwidth(char far *str): 
功能:以像素为单位,返回由str所指向的字符串宽度,针对当前字符的字体与大小。
该程序用到的dos.h中的库函数有delay(),其原型说明如下: 
void delay(unsigned milliseconds) 
功能:该函数将程序的执行暂停一段时间(毫秒)。 
void far random(int num) 
功能:此函数返回一个0~num 范围内的随机数。该函数在stdlib.h库中。
3.3.2 动态开辟视图窗口的方法
我们还可以利用视图窗口设置技术来实现视图窗口动画效果,具体方法是:在不同视
图窗口中设置同样的图像,然后让视图窗口沿x轴方向移动设置,这次出现前要清除上次视
图窗口的内容,这样就会出现图像沿x轴移动的效果。也就是说,在位置动态变化但大小不
变的视图窗口中(用setviewport()函数),设置固定图形(也可是微小变化的图像),这样虽
呈现在观察者面前的是当前视图窗口位置在动态变化,但视觉上却像是看到图像在屏幕上
动态变化一样。
例3-2就是这样做的,不断地沿x轴开辟视图窗口,就像一个大小一样的窗口沿x轴在
移动,由于总有clearviewport函数清除上次窗口的相同立方体,因而视觉效果上,就像一个
立方体从左向右移动一样。程序中定义的movebar函数作用是开辟一个视图窗口,并画一
个填色的立方体,保留一阵(delay(250000))然后清除它,主程序不断调用它,因每次顶点x 
坐标在增加,因而效果是立方体沿x轴从左向右在运动。
例3-2 
#include<graphics.h> 
#include<dos.h> 
main() 
{ 
int i,driver,mode; 
graphdriver=DETECT; 
initgraph(&driver,&mode,""); 
for(i=0;i<25;i++) 
{ 
setfillstyle(1, i); 
movebar(i * 20); 
} 
closegraph(); 
}m
ovebar(int xorig) /*设窗口并画填色小立方体*/

61 
{ 
setviewport(xorig,0,639,199,1); 
setcolor(5); 
bar3d(10,120,60,150,40,1); 
floodfill(70,130,5); 
floodfill(30,110,5); 
delay(250000); 
clearviewport(); 
}
采用上面的两种方法对较复杂图形不适宜,一则画图形要占较长时间,二则视图窗口位
置切换的时间变得较长,因而动画效果就会变差。
3.3.3 屏幕图像存储再放的方法
在图形方式下,与文本方式类似,除了清屏函数cleardevice()外,还有其他的对屏幕图
像操作的函数。其中一类是屏幕图像存储和显示函数,包括:存屏幕图像到内存区
getimage()函数,测定图像所占字节数的imagesize()函数,将所存图像显示的putimage() 
函数,函数详情见3.1.3节。
例3-3演示了动画的工作方式,for循环用来在屏幕上方产生连续的五个方框,方框中
套用洋红色填充的小方块,五个图像全一样。循环结束后,又在屏幕下方画出两个小框,小
框用洋红色填充并在大框内。程序运行后,立即在屏幕上显示出上述图案,当按任意键后, 
则由函数imagesize()得到屏幕下方大框区域内图像所占字节数,然后由malloc()函数按字
节数分配内存缓冲区buffer,再由getimage()函数将图像存到buffer中,然后复制到屏幕上
方左边第一个框位置。按任意键后,又将buffer中图像和第二个框图像进行与操作后显
示,再按任意键,buffer中的图像又和第三个方框内图像进行或操作并显示,如此重复,则可
将5种逻辑操作结果均显示在屏幕上。
注意:COPY和NOT操作将与原来屏幕上的图像无关,buffer中图像经过这两种操
作,将覆盖掉原屏幕上图像,并将结果进行显示。
例3-3 
#include<graphics.h> 
main() 
{ 
int i,j,driver,mode,size; 
void *buffer; 
driver=DETECT; 
initgraph(&driver,&mode,""); 
setbkcolor(BLUE); 
cleardevice(); 
setcolor(YELLOW); 
setlinestyle(0,0,1); /*用细实线*/ 
setfillstyle(1,5); /*用洋红色实填充*/ 
for(i=0;i<5;i++) /*产生连续的五个方框中套小框*/

62 
{ 
j=i *110; 
rectangle(80+j,100,130+j,150); /*产生小框且用洋红色填充*/ 
floodfill(110+j,140,YELLOW); 
rectangle(50+j,100,130+j,180); /*画大框*/ 
}r
ectangle(50,340,100,420); /*产生一个小框*/ 
floodfill(80,360,YELLOW); /*用洋红色填充*/ 
rectangle(50,340,130,420); /*产生一个大框*/ 
getch(); 
size=imagesize(40,300,132,430);
/*取得(40,300)右下角(132,430)区域图像字节数*/ 
buffer=malloc(size); /*分配缓冲区(按字节数)*/ 
getimage(40,300,132,430,buffer); /*存图像*/ 
putimage(40,60,buffer,COPY_PUT); /*重新复制*/ 
getch(); 
j=110; 
putimage(40+j,60,buffer,AND_PUT); /*和屏幕上的图与操作*/ 
getch(); 
putimage(40+2*j,60,buffer,OR_PUT); 
getch(); 
putimage(40+3*j,60,buffer,XOR_PUT); 
getch(); 
putimage(40+4*j,60,buffer,NOT_PUT); 
getch(); 
closegraph(); 
}
同制作幻灯片一样,将整个动画过程变成一个个片断,然后存到显示缓冲区内,当把它
们按顺序重放到屏幕上时,就出现了动画效果,这可以用getimage()和putimage()函数来
实现,这种方法较快,因它已事先将要重放的画面画好了。余下的问题,就是计算应在什么
位置重放的问题了。
例3-4演示了利用这种方法产生的两个洋红色小球碰撞、弹回然后又碰撞的动画效果。
例3-4 
#include<graphics.h> 
main() 
{ 
int i,driver,mode,size; 
void *buffer; 
driver=DETECT; 
initgraph(&driver,&mode,""); 
setbkcolor(BLUE); 
cleardevice(); 
setcolor(YELLOW);

63 
setlinestyle(0,0,1); 
setfillstyle(1,5); 
circle(100,200,30); 
floodfill(100,200,YELLOW); /*填充圆*/ 
size=imagesize(69,169,131,231); /*指定图像占字节数*/ 
buffer=malloc(size); /*分配缓冲区(按字节数)*/ 
getimage(69,169,131,231,buffer); /*存图像*/ 
putimage(500,169,buffer,COPY_PUT); /*重新复制*/ 
do{ 
for(i=0;i<185;i++) 
{ 
putimage(70+i,170,buffer,COPY_PUT); /*左边球向右运动*/ 
putimage(500-i,170,buffer,COPY_PUT); /*右边球向左运动*/ 
} /*两球相撞后循环停止*/ 
for(i=0;i<185;i++) 
{ 
putimage(255-i,170,buffer,COPY_PUT); /*左边球向左运动*/ 
putimage(315+i,170,buffer,COPY_PUT); /*右边球向右运动*/ 
} 
}while (!kbhit()); /*当不按键时重复上述过程*/ 
getch(); 
closegraph(); 
} 
3.3.4 利用页交替的方法
对屏幕图像操作的函数,还有一类是设置显示页函数。显示适配器的显示存储器为
VRAM,图形方式下存储在VRAM 中的一满屏图像信息称为一页。每页一般为64K字节, 
图3.1 显示页
VRAM 可以存储要显示的图像几页(视VRAM 
容量而定,最大可达8页),TurboC2.0支持页的
功能有限,按在图形方式下显示的模式最多支持
4页(EGALO 显示方式),一般为2 页(注意对
CGA,仅有1页),因存储图像的页显示时,一次
只能显示1页,因此必须设定某页为当前显示的
页(又称可视页),缺省时定为0 页,如图3.1 
所示。正
在由用户编辑图形的页称为当前编辑页(又称激活的页),这个页不等于显示页,即若
用户不设定该页为当前显示页时,在该页上编辑的图形将不会在屏幕上显示出来。缺省时, 
设定0页为当前编辑页,即若不用下述的页设置函数进行设置,就认定0页既是编辑页,又
是当前显示页。
设置激活页和显示页的函数为setactivepage()和setvisualpage(),详情见3.1.3节。这
两个函数只能用于EGA、VGA 等显示适配器。前者设置由pagenum 指出的页为激活的

64 
页,后者设置可显示的页。当设定了激活的页,即编辑页后,则程序中其后的画图操作均在
该页进行,若它不定为显示页,则其上的图像信息并不会在屏幕上显示出来。
例3-5的程序演示了设置显示页函数的应用。首先用setactivepage(1)设置l页为编
辑页,在上面画出一个红色边框、用淡绿色填充的圆,此图并不显示出来(因缺省时,定义0 
页为可视页)。接着又定义0页为编辑页并清屏(即清0页),也定义0页为可视页,并在其
上画出一个用洋红色填充的方块,该方块将在屏幕上显示出来。接着进入do循环,设置l 
页为可视页,因而其上的圆便在屏幕上显示出来,方块的图像消失,用delay(2000)将圆图像
保持2000毫秒即2秒,当不按键时,下一次循环又将0页设为可视页,因而方块的图像显示
出来,圆图像又消失。保持2秒后,又重复刚开始的过程。这样我们就会看到:屏幕上同一
位置洋红色方块和淡绿色圆交替出现,若将delay时间变少,将会出现动画的效果。
例3-5 
#include<graphics.h> 
#include<dos.h> 
main() 
{ 
int i,graphdriver,graphmode,size,page; 
graphdriver=DETECT; 
initgraph(&graphdriver,&graphmode,""); 
cleardevice(); 
setactivepage(1); /*设置l 页为编辑页*/ 
setbkcolor(BLUE); 
setcolor(RED); 
setfillstyle(1,10); 
circle(130,270,30); /*画圆*/ 
floodfill(130,270,4); /*用淡绿色填充圆*/ 
setactivepage(0); /*设置0 页为编辑页*/ 
cleardevice(); /*清0 页*/ 
setfillstyle(1,5); 
bar(100,210,160,270); /*画方块并填充洋红色*/ 
setvisualpage(0); /*设置0 页为可视页*/ 
page=1; 
do 
{ 
setvisualpage(page); /*显示设定页的图像*/ 
delay(2000); /*延迟2000ms*/ 
page=page-1; 
if(page<0) 
page=1; 
} while(!kbhit()); 
getch(); 
closegraph(); 
}