当前位置: 首页 > 科技观察

如何使用ncurses进行颜色编程

时间:2023-03-20 17:28:43 科技观察

Jim为他的终端冒险添加了颜色,演示了如何使用curses操作颜色。在我关于使用ncurses库进行编程的系列文章的第1部分和第2部分中,我介绍了一些用于在屏幕上绘图、查询屏幕和从键盘读取字符的curses函数。为了弄清楚这些功能,我创建了一个简单的冒险游戏,使用curses来绘制游戏地图和使用简单字符的玩家角色。在这篇后续文章中,我展示了如何为您的curses程序添加色彩。在屏幕上绘图固然很好,但如果只有黑白文本,您的程序可能看起来很乏味。颜色可以帮助传达更多信息。例如,如果您的程序需要报告成功或失败。在这种情况下,您可以使用绿色或红色来帮助强调输出。或者,您只是想让您的程序看起来更美观。在这篇文章中,我使用一个简单的示例来演示通过curses函数进行的颜色操作。在我之前的文章中,我写了一个基本的冒险游戏,可以让你在粗略绘制的地图上移动玩家角色。但是那里的地图完全是黑白文字,形状表示水(~)或山(^)。因此,让我们将游戏更新为使用颜色的版本。颜色元素在你可以使用颜色之前,你的程序需要知道它是否可以依赖终端来正确显示颜色。在现代操作系统上,这里应该始终如此。但在经典计算机上,有些终端是单色的,例如古老的VT52和VT100终端,它们通常提供黑底白字或黑底绿字。可以使用has_colors()函数查询终端的颜色功能。如果终端可以显示颜色,此函数将返回true,否则将返回false。这个函数一般用在if块的开头,像这样:if(has_colors()==FALSE){endwin();printf("你的终端不支持彩色\n");exit(1);}终端可以显示颜色后,可以使用start_color()函数设置curses使用颜色。现在是时候定义程序将使用的颜色了。在curses中,您应该成对定义颜色:背景色之上的前景色。这允许curses一次设置两个颜色属性,这通常是您想要做的。通过init_pair()函数,可以定义前景色和背景色,并将它们与索引号相关联,从而设置颜色对。一般语法如下:init_pair(index,foreground,background);控制台支持八种基本颜色:黑色、红色、绿色、黄色、蓝色、品红色、青色和白色。这些颜色使用以下名称为您定义:COLOR_BLACKCOLOR_REDCOLOR_GREENCOLOR_YELLOWCOLOR_BLUECOLOR_MAGENTACOLOR_CYANCOLOR_WHITE应用颜色在我的冒险游戏中,我希望草地显示为绿色,玩家的脚步声为绿色背景上的微妙黄点。水应该是蓝色的,那些代表波浪的符号应该是近似青色的。我希望山(^)是灰色的,但我可以在白色背景上使用黑色文本做出可用的妥协。(LCTT译注:意思是终端的默认颜色不是灰色,使用白底黑字作为妥协)为了让玩家的性格更显眼,我想使用大胆的洋红色设计。我可以这样定义这些颜色对:start_color();init_pair(1,COLOR_YELLOW,COLOR_GREEN);init_pair(2,COLOR_CYAN,COLOR_BLUE);init_pair(3,COLOR_BLACK,COLOR_WHITE);init_pair(4,COLOR_RED,COLOR_MAGENTA);为了让颜色对更容易记住,我的程序中定义了一些符号常量:#defineGRASS_PAIR1#defineEMPTY_PAIR1#defineWATER_PAIR2#defineMOUNTAIN_PAIR3#definePLAYER_PAIR4有了这些常量,我的颜色定义就变成了:start_color();init_pair(GRASS_PAIR,COLOR_YELLOW,COLOR_GREEN);init_pair(WATER_PAIR,COLOR_CYAN,COLOR_BLUE);init_pair(MOUNTAIN_PAIR,COLOR_BLACK,COLOR_WHITE);init_pair(PLAYER_PAIR,COLOR_RED,COLOR_MAGENTA);文本,你只需要告诉curses要设置哪个颜色属性。为了更好的编程实践,您还应该告诉curses在您使用完颜色后取消组合颜色。为了设置颜色,应该在调用像mvaddch()这样的函数之前使用attron(),然后通过attroff()关闭颜色属性。例如,当我绘制玩家角色时,我应该这样做:attron(COLOR_PAIR(PLAYER_PAIR));mvaddch(y,x,PLAYER);attroff(COLOR_PAIR(PLAYER_PAIR));请记住将颜色应用于您的程序对您查询屏幕的方式有一些微妙的影响。一般来说,mvinch()函数返回的值是没有color属性的类型chtype,基本上是一个整型值,也可以作为整型值使用。但是,由于颜色的使用为屏幕上的字符添加了额外的属性,因此chtype在扩展位模式中携带了额外的颜色信息。使用mvinch()后,返回值将包含这些额外的颜色值。为了仅提取文本值,例如在is_move_okay()函数中,您需要对A_CHARTEXT进行&按位运算:intis_move_okay(inty,intx){inttestch;/*如果空间可以移入则返回true*/testch=mvinch(y,x);return(((testch&A_CHARTEXT)==GRASS)||((testch&A_CHARTEXT)==EMPTY));}通过这些修改,我可以用颜色更新这个冒险游戏:/*quest.c*/#include#include#defineGRASS''#defineEMPTY'.'#defineWATER'~'#defineMOUNTAIN'^'#definePLAYER'*'#defineGRASS_PAIR1#defineEMPTY_PAIR1#defineWATER_PAIR2#defineMOUNTAIN_PAIR3#definePLAYER_PAIR4intis_move_okay(inty,intx);voiddraw_map(void);int主(无效){inty,x;内部通道;/*初始化curses*/initscr();键盘(stdscr,真);中断();没有回声();/*初始化颜色*/if(has_colors()==FALSE){endwin();printf("你的终端不支持彩色\n");退出(1);}开始颜色();init_pair(GRASS_PAIR、COLOR_YELLOW、COLOR_GREEN);init_pair(WATER_PAIR,COLOR_CYAN,COLOR_BLUE);init_pair(MOUNTAIN_PAIR,COLOR_BLACK,COLOR_WHITE);init_pair(PLAYER_PAIR,COLOR_RED,COLOR_MAGENTA);清除();*在左下角创建新字符*/y=LINES-1;x=0;do{/*默认情况下你会得到一个闪烁的光标——表示玩家*/attron(COLOR_PAIR(PLAYER_PAIR));mvaddch(y,x,播放器);attroff(COLOR_PAIR(PLAYER_PAIR));移动(y,x);刷新();ch=getch();/*测试输入键值并获取方向*/switch(ch){caseKEY_UP:case'w':case'W':if((y>0)&&is_move_okay(y-1,x)){attron(COLOR_PAIR(EMPTY_PAIR));mvaddch(y,x,空);attroff(COLOR_PAIR(EMPTY_PAIR));y=y-1;}休息;案例KEY_DOWN:案例's':案例'S':如果((y0)&&is_move_okay(y,x-1)){attron(COLOR_PAIR(EMPTY_PAIR));mvaddch(y,x,空);attroff(COLOR_PAIR(EMPTY_PAIR));x=x-1;}休息;caseKEY_RIGHT:case'd':case'D':if((xreturn((testch==GRASS)||(testch==EMPTY));140d108