分类: LINUX
2011-07-14 14:52:00
//////////////////////////////////////////////////////////////////////////
学习要点:
(1)基本使用方法
(2)窗口与子窗口
(3)Keypad模式、颜色显示和Pad
//////////////////////////////////////////////////////////////////////////
Curses 标准作为过渡,位于简单的文本行程序和完全图形化界面(一般也更难于编程)的 X 视窗系统程序(如 GTK/GNOME 和 Qt/KDE )之间。 Curses 函数库的名称来自它所提供的功能,它能够优化光标的移动并减少需要对屏幕进行的刷新,因此它也减少了必须向字符终端发送的字符数目。 基本使用方法 Curses 例程工作在屏幕、窗口和子窗口上。所谓“屏幕”就是正在写的设备(通常是终端屏幕,也有可能是 xterm 屏幕)。 Curses 函数库使用两个数据结构来映射终端屏幕,它们是 stdscr 和 curscr 。其中 stdscr 数据结构对应的是“标准屏幕”,它的工作原理和 stdio 函数库中的标准输出 stdout 非常相似,它是 curses 程序中的默认输出插口;而 curscr 数据结构和 stdscr 相似,但它对应的是当前屏幕的样子。 一个使用 curses 函数库的典型例程如下: #include #include #include int main() { initscr(); move(5,15); printw("%s", "Hello World!"); refresh(); endwin(); exit(0); } 当对使用 curses 函数库的程序进行编译时,必须在程序中包含头文件 curses.h ,它是需要在编译命令行中用 -lcurses 选项对 curses 函数库进行链接。 从上面的程序可以看到,所有 curses 程序必须以初始化函数 initscr 开始,以函数 endwin 结束。函数 initscr 在一个程序中只能调用一次。 提示 :我们可以先调用 endwin 函数退出 curses ,然后通过调研 clrearok(strscr,1) 和 refresh 函数继续 curses 操作。这样,实际上是首先让 curses 忘记物理屏幕的样子,然后强迫它执行一次完整的屏幕原文重现。 函数 move 和 printw 的功能是移动光标和在当前位置上输出文本。在调用 refresh 函数之前,输出到 stdscr 上的内容是不会显示在屏幕上的。 refresh 函数的作用就是刷新物理屏幕。 当需要在屏幕上显示比较松散的多行文本时,典型方式就是通过 move 函数与 printw 函数的配合来完成。 简单来说, Curses 函数库有几种函数:屏幕输出函数、输入函数、清除函数和光标移动函数。通过这几种函数的配合,我们就可以实现一个简单的全屏界面。 字符属性 :每个 curses 字符都可以有特定的属性,该属性控制着该字符在屏幕上的显示方式,前提是用于显示的硬件设备能够支持要求的属性。预定义的属性有 A_BLINK 、 A_BOLD 、 A_DIM 、 A_REVERSE 、 A_STANDOUT 和 A_UNDERLINE 。相关函数有 attron 、 attroff 和 attrset 等。一个典型的使用片段如下: move(5,15); attron(A_BOLD); printw("%s", "Hello World!"); attroff(A_BOLD); refresh(); 键盘 : curses 函数库还提供了控制键盘的简单方法。通过调用两个 echo 函数,我们可以简单地关闭或开启输入字符的回显功能。通过调用 break 函数,可以将输入模式设置为字符中止模式,在这种模式下,字符一经键入立刻传递给程序,而不是像在行模式中那样首先缓存字符,知道用户按下回车键才将用户输入的字符传递给程序。通过调用两个 raw 函数则可以关闭或开启特殊字符的处理。 提示 : curses 环境下,输入模式分行模式和字符中止模式。默认输入模式是行模式,当用户键入回车符时才会将输入的数据传递给程序;而字符中止模式则当字符一经键入就传递给程序。 窗口与子窗口 Curses 函数库在物理屏幕上能够同时显示多个不同尺寸的窗口。 在 curses 环境下,窗口由 WINDOW 数据结构来表示。实际上,标准屏幕 stdscr 只是 WINDOW 结构的一个特例。下面是一个使用了窗口的例程 #include #include #include int main() { WINDOW *new_window; int x,y; char letter = 'a'; initscr(); for(y=0;y { for(x=0;x { mvwaddch(stdscr, y, x, letter); if(++letter > 'z') letter = 'a'; } } refresh(); sleep(2); new_window = newwin(10,20,5,5); box(new_window, '|', '-'); mvwprintw(new_window, 2, 2, "%s", "Hello World"); wrefresh(new_window); sleep(2); mvwin(new_window, 10, 10); wrefresh(new_window); sleep(2); delwin(new_window); endwin(); return 0; } 上面的例程中,先在全屏幕上填满字符,然后创建一个 10*20 的新窗口,继而在新窗口上输出“ Hello , World ”。 新窗口的建立是由 newwin 函数来实现的,它指定了新窗口的大小和位置。删除一个窗口时则使用 delwin 函数。函数 box 的作用在于使用特殊的字符来界定新窗口。 用于窗口的通用函数有几类:前缀 w 用于窗口、前缀 mv 用于光标移动、前缀 mvw 用于在制定窗口中移动光标。 wrefresh 函数用于刷新窗口。而 mvwin 函数的作用是移动指定的窗口到指定的位置;如果移动后窗口超出屏幕范围, mvwin 函数调用将会失败。 子窗口 是多窗口的一种特例,我们使用 subwin 函数和 delwin 函数创建和删除子窗口。与前面提到的新窗口相比,子窗口没有自己独立的屏幕字符存储空间,它们与它们的父窗口(在调用 subwin 时指定)共享同一字符存储空间。这意味着,对子窗口中内容的任何修改都会反映到它的父窗口中,所以删除子窗口时,屏幕不会发生任何变化。 子窗口主要的用途是提供了一种简洁的方式来卷动另一窗口里的部分内容。在编写 curses 程序时,经常需要卷动屏幕的某个小区域,将这个小区域定义为一个子窗口,然后对其卷动,就能达到我们想要的效果。 注意 :使用子窗口有个强加的限制:在应用程序刷新屏幕之前必须先对其父窗口调用 touchwin 函数。 keypad 模式 curses 函数库提供了一个精巧的用于管理功能键的功能。对每个终端来说,它的每个功能键所对应的转义序列都被保存,通常是保存在一个 terminfo 结构中,而头文件 curses.h 通过一组以 KEY_ 为前缀的定义来管理逻辑键。 curses 在启动时会关闭转义序列与逻辑键之间的转换功能,这功能需要通过调用 keypad 函数来启用。 实际上,使用 keypad 模式还是有一定的限制的: 1 )识别 escape 转义序列的过程是与时间相关的。在处理许多网络协议时这个问题会变得很突出,唯一解决办法是设法对终端进行编程,让它针对用户希望使用的每个功能键只发送一个单独的、唯一的字符,但这将限制可使用的控制字符的数目。 2 )为了让 curses 能够区分“单独按下 Escapce 键”和“一个以 Escape 字符开头的键盘转义字符”,它必须等待一小段时间。 3 ) curses 不能处理二义性的 Escape 转义序列。如果你的终端上两个不同的按键会产生完全相同的转义序列,就回导致 curses 不知该返回哪个逻辑按键。 Curses 对这一问题的处理方式是简单地放弃对这个转义序列的处理。 彩色显示 鉴于历史性原因, curses 只能以一种非常受限的方式来使用彩色。 Curses 函数库对颜色的支持有些不同:字符颜色的定义及其背景色的定义并不完全独立。必须同时定义一个字符的前景色和背景色,称为颜色组合。 把颜色作为字符属性使用之前,必须首先调用 init_pair 函数对装备使用的颜色组合进行初始化,而对颜色属性的访问则通过 COLOR_PAIR 函数来完成。而颜色属性的激活则由 wattron 函数来完成,它的第二个参数指定了需要设置的颜色属性。 Pad 在编写高级 curses 程序时,有时需要先建立一个逻辑屏幕,然后再把它的全部或者部分内容输出到物理屏幕上。 Curses 提供了一个特殊的数据结构 pad 来解决这个问题。 Pad 结构非常类似于 WINDOW 结构,所有执行写窗口操作的 curses 函数同样可以应用于 pad 。但是 pad 有自己的创建函数 newpad 和刷新函数 prefresh 。 本章最后展示了一个 CD 唱片应用程序的完整代码。它详细地描述了如何使用 curses 来编写应用程序,为我们自己设计使用 curses 函数库带来了很大的帮助。