1CodeBlock下的人机交互界面设计人机交互界面指的是计算机系统与用户之间的接口。通过该接口,一方面,计算机系统向用户输出系统的运行状态、运行控制和运行结果等方面信息;另一方面,用户根据输出信息向系统输入相应的指令和数据等信息。3.4.1控制台窗口和屏幕缓冲区控制台窗口是个二维平面空间,其坐标系统的原点(0,0)设在窗口左上角,即窗口第一行第一列字符单元的位置。横轴(X轴)的正向沿原点向右,与窗口的第一行重合,每刻度为一个字符宽度;纵轴(Y轴)的正向沿原点向下,与窗口的第一列重合,每刻度为一个字符高度。窗口中每个字符单元对应一个二维坐标。比如,第5行第32列字符单元的坐标为(31,4)。如图3.8所示。内存映像显示器屏幕区控制台窗口区X轴Y轴(0,0)(31,4)第5行第32列N列M行B(0,0)B(0,1)B(0,2)………………B(0,N-1)B(1,0)B(1,1)B(1,2)………………B(1,N-1)B(2,0)B(2,1)B(2,2)………………B(2,N-1)………………………………………………………………………B(M-1,0)B(M-1,1)B(M-1,2)……B(M-1,N-1)激活的屏幕缓冲区非激活的屏幕缓冲区窗口标题栏图3.8控制台窗口和屏幕缓冲区关系示意图屏幕缓冲区是个二维数组,逻辑上可看作一个二维平面空间。数组第一个元素的下标[0][0]对应此平面空间坐标系统的原点(0,0),数组第1维的下标对应坐标系统的纵坐标(Y坐标),第2维下标对应坐标系统的横坐标(X坐标)。屏幕缓冲区存放着M行N列字符单元的信息,M和N的大小由系统设置,并可以进行修改。每个字符单元信息用一个CHAR_INFO结构类型的数据来表示,结构成员Char存放字符的码值(Unicode码或ASCII码,取决于系统所采用的字符集),结构成员Attributes存放字符的属性(字符显示所用的前景色和背景色)。操作系统以一定的频率从屏幕缓冲区读取字符单元信息,并显示在控制台窗口中。应用程序的输出信息实际上输出到了屏幕缓冲区,由此改变了控制台窗口所显示的内容。初始状态下,屏幕缓冲区坐标系统与控制台窗口坐标系统重合,窗口中第m行第n列字符的码值和颜色值存放在屏幕缓冲区二维数组中下标为[m-1][n-1]的元素中。利用控制台函数可以改变这两个坐标系统的对应关系,实现特殊的显示效果。图3.8表示了控制台窗口和屏幕缓冲区的相互关系。2一个控制台可拥有多个屏幕缓冲区,但只有处于激活状态的屏幕缓冲区内容显示在控制台窗口中。操作系统在为进程创建控制台的同时会创建一个屏幕缓冲区。进程可调用函数CreateConsoleScreenBuffer为其控制台创建另外的屏幕缓冲区。调用函数SetConsoleActiveScreenBuffer可以将某个已有的屏幕缓冲区置为激活状态,使其内容显示在屏幕窗口中。不管是否处于激活状态,屏幕缓冲区都可以通过句柄来进行读写操作,只不过激活状态下屏幕缓冲区的内容可以看到,非激活状态下看不到而已。屏幕缓冲区相关的多个属性可以独立进行设置。激活的屏幕缓冲区属性值的变化能在控制台窗口中产生奇妙的外观效果。屏幕缓冲区相关的属性包括:屏幕缓冲区大小,以字符行和列为单位;文本属性(文本信息显示的前景色和背景色);窗口大小和定位(控制台屏幕缓冲区在控制台窗口中显示时所处的矩形区域);光标位置、外观和是否可见;输出模式(控制字符的输出处理和行末换行处理)。屏幕缓冲区在创建时,它所包含的字符内容初始化为空格,光标设为可见并定位在缓冲区原点(0,0),而窗口的原点(左上角)与缓冲区原点置为重合。控制台屏幕缓冲区的大小、窗口的大小、文本属性和光标的外观取决于用户或系统的缺省设置。为获取控制台屏幕缓冲区各种相关属性的当前值,可分别调用函数:GetConsoleScreenBufferInfo;GetConsoleCursorInfo;GetConsoleMode。屏幕缓冲区光标信息用CONSOLE_CURSOR_INFO结构类型的数据表示,成员bVisible表示光标是否可见,成员dwSize表示光标外观大小,取值范围为1~100。光标可见时,dwSize的取值从100变为1,光标外观大小从充满整个字符单元变为出现在单元底部的一条水平线。调用函数GetConsoleCursorInfo和SetConsoleCursorInfo分别可以获得和设置光标属性值。由高级控制台I/O函数(如getchar,putchar,printf,scanf等)输出的字符将输出在光标当前位置,同时光标移动到下一个字符输出位置。调用函数:GetConsoleScreenBufferInfo和SetConsoleCursorPosition,分别可以获得和设置光标在屏幕缓冲区坐标系统中的当前位置,由此可以控制高级I/O函数输出或回显字符的位置。字符属性分为两类:颜色属性和DBCS(Double-ByteCharacterSet,双字节字符集)属性。表3.14中的符号常量在wincon.h头文件中进行定义。表3.14字符属性符号常量表属性含义FOREGROUND_BLUE文本颜色包含蓝色FOREGROUND_GREEN文本颜色包含绿色FOREGROUND_RED文本颜色包含红色FOREGROUND_INTENSITY文本颜色加亮BACKGROUND_BLUE背景含蓝色BACKGROUND_GREEN背景含绿色BACKGROUND_RED背景含红色BACKGROUND_INTENSITY背景加亮COMMON_LVB_LEADING_BYTE首字节COMMON_LVB_TRAILING_BYTE末字节3COMMON_LVB_GRID_HORIZONTAL首行COMMON_LVB_GRID_LVERTICAL左列COMMON_LVB_GRID_RVERTICAL右列COMMON_LVB_REVERSE_VIDEO翻转前景及背景属性COMMON_LVB_UNDERSCORE下划线前缀为FOREGROUND的常量值指定文本颜色(文本的前景色)。前缀为BACKGROUND的常量值指定用于填充字符单元背景的颜色。其他常量值用于DBCS属性。应用程序可以将前景色和背景色常量值组合起来,获得不同颜色。例如,下面颜色组合的效果为蓝色背景上的亮青色文本。FOREGROUND_BLUE|FOREGROUND_GREEN|FOREGROUND_INTENSITY|BACKGROUND_BLUE如果不指定背景颜色值,那么背景为黑色,而不指定前景颜色值,文本为黑色。例如,下面颜色组合将产生白色背景上的黑色文本效果。BACKGROUND_BLUE|BACKGROUND_GREEN|BACKGROUND_RED每个屏幕缓冲区字符单元储存了在“画”该单元的文本(前景)和背景时所使用的颜色属性值。应用程序可以分别设置每个字符单元的颜色值,并将颜色值存储在每个单元CHAR_INFO结构类型数据的Attributes成员中。屏幕缓冲区的当前文本属性对随后使用高级I/O函数输出或回显的字符产生作用。调用函数GetConsoleScreenBufferInfo可得到当前屏幕缓冲区的文本属性值,而调用函数SetConsoleTextAttribute可设置字符属性值。改变屏幕缓冲区文本属性不会对当前已经输出字符的颜色产生影响。同时文本属性不会对低级控制台I/O函数(如函数WriteConsoleOutput或WriteConsoleOutputCharacter)输出的字符产生影响,低级控制台I/O函数输出字符的颜色取决于输出位置上的字符属性值。3.4.2在屏幕上指定位置输出信息有多种方法在屏幕指定位置输出带属性的字符串信息,这里介绍其中四种基本方法。(1)用标准输出函数(putchar,printf,puts等)输出字符串信息;//设置光标位置SetConsoleCursorPosition(output_handle,new_pos);//输出字符串stringprintf(“%s”,string);//在字符串输出位置填充指定的文本属性FillConsoleOutputAttribute(output_handle,new_attributes,strlen(string),new_pos,NULL);其中output_handle是屏幕缓冲区句柄,new_pos为COORD类型的变量,存放指定的光标位置坐标,new_attributes为WORD类型的变量,存放指定的文本属性值,string是字符数组,存放被输出的字符串。(2)用函数WriteConsole输出字符串信息;//设置光标位置SetConsoleCursorPosition(output_handle,new_pos);//设置文本属性SetConsoleTextAttribute(output_handle,new_attributes);4//输出字符串WriteConsole(output_handle,string,strlen(string),NULL,NULL);变量的含义同上。(3)用函数WriteConsoleOutputCharacter输出字符串信息;//在指定位置填充与所输出字符串等长的文本属性值FillConsoleOutputAttribute(output_handle,new_attributes,strlen(string),new_pos,NULL);//在该指定位置输出字符串WriteConsoleOutputCharacter(output_handle,string,strlen(string),new_pos,NULL);(4)用函数WriteConsoleOutput输出字符串信息;CHAR_INFO*lpBuffer;COORDpos={0,0};COORDsize={strlen(string),1};SMALL_RECTarea={new_pos.X,new_pos.Y,new_pos.X+strlen(string)-1,new_pos.Y};lpBuffer=(CHAR_INFO*)malloc(size.X*size.Y*sizeof(CHAR_INFO));for(i=0;istrlen(string);i++){lpBuffer-Char.AsciiChar=string[i];lpBuffer-Attributes=new_attributes;}WriteConsoleOutput(output_handle,lpBuffer,size,pos,&area);free(area);这种方法使用起来相对复杂一些。基本思想是将输出信息当作一个矩形字符信息块,设置矩形块的大小size,矩形块在窗口中的输出位置area,将矩形块内字符信息存放在一个动态存储缓冲区lpBuffer内,字符信息包含了字符的码值和颜色属性,最后调用函数WriteConsoleOutput将lpBuffer中字符块信息写到控制台屏幕缓冲区指定位置。前两种方法所调用的函数printf和WriteConsole属于高级I/O函数,而后两种方法所调用的函数WriteConsoleOutputCharacter和WriteConsoleOutput则是低级I/O函数。这四种基本方法的区别在于字符串输出位置的设置、字符串颜色属性的设置和字符串内容的输出三个方面。实际应用中,这些方法结合起来使用,可以获得特别的输出效果。例3.1文本菜单界面的初始化。#includedorm.hintmain(){COORDsize={ScrCol,ScrRow};//窗口缓冲区大小WORDatt=FOREGROUND_RED|FOREGROUND_GREEN|FOREGROUND_INTENSITY|BACKGROUND_BLUE;hOut=GetStdHandle(STD_OUTPUT_HANDLE);//获取标准