- 论坛徽章:
- 1
|
1.什么是Curses
Curses -- CRT屏幕处理和优化软件包,它包含许多例程.
Curses库例程给程序员一个不依赖特定终端的方法来合理优化更新字符屏幕.幕后功臣为terminfo/termcap.
2.Curses包的功能
.全部的屏幕窗口基垫的操作
.向窗口和基垫的输出
.读取终端的输入
.控制终端和curses的输入输出选项
.环境查询例程
.颜色操纵
.软标签的使用
.terminfo访问
.访问低层curses例程
3.开始使用curses
要想使用curses,必须将其初始化,就是在使用curses其它例程之前,必须先调用initscr()或new_term()例程.initscr()初始化curses,设定必要的变量,返回一个WINDOW结构指针.下面是一个典型的初始化流程.
int slk_you = 0;
WINDOW *cl_initwindow(slk_flag)
int slk_flag;
{
int i;
if(slk_flag) {
slk_init(SLK_CENT);
for(i = 1; i 0) {
wmove(w, begin++, 0);
wclrtoeol(w);
}
}
它从一行的开头清除到行尾,一共可以清除lines行,这样可以如下调用来清除提示信息:
cl_clearline(msgwin, 0, 1);
当我们希望给用户一个操作提示之后,等待他确认操作有效性时,可以利用下面的函数:
int cl_yesno(win, y, x, prmp, defau)
WINDOW *win;
int y, x;
char *prmp;
char defau;
{
int ch;
ch = defau == 'Y' || defau == 'y'? 'Y' : 'N';
mvwprintw(win, y, x, "%s(Y/N): [%c]", prmp, ch);
wmove(win, y, x = win->_curx - 2);
wrefresh(win);
while(1) {
switch(wgetch(win)) {
case 'Y' :
case 'y' :
case '1' :
ch = 'Y';
break;
case 'N' :
case 'n' :
case '0' :
case 'q' :
case 'Q' :
ch = 'N';
break;
case '\r' :
break;
default :
beep();
continue;
}
waddch(win, ch);
wrefresh(win);
return ch == 'Y';
}
}
这个函数有一些技巧,他在提示时提供个默认值'Y'或'N',然后利用WINDOW结构成员_curx使光标移动回默认值之下,等待用户按键,除指定的那些键之外都不反应,最后返回ch是否等于'Y'.
有时在程序中硬编码提示信息很不方便,因为提示变更时你得重新编辑编译程序,所以我们将提示信息加到一个文本文件中,由一个字符串标识,这样在程序中可以使用该标识字符串来引用提示信息,而信息的实际内容在文本文件中,可以随时更改,文件内容可以着样:
E001|无法打开指定表单!
E002|此域不能为空!
.
.
.
前面为提示信息的标识符,后面是要在终端显示的具体内容,现在关键是我们怎样在程序中利用标识符来引用提示信息.
因为在文件中使用了一个分隔符'|',所以在程序中要用grep来提取,然后要用到一个按分隔符分解字符串的函数:
CLERROR *ut_geterror(errseri)
char *errseri;
{
int i;
int pos = 0;
char *errorstr;
char *pipecmd;
CLERROR *errlist;
FILE *pfp;
errlist = (CLERROR *)calloc(ERR_NUM + 1, sizeof(CLERROR));
pipecmd = (char *)malloc(100);
memset(pipecmd, 0, 100);
errorstr = (char *)malloc(100);
memset(errorstr, 0, 100);
sprintf(pipecmd, "grep %s ../../etc/Clerror.ch | tail -1", errseri);
if((pfp = popen(pipecmd, "r")) == NULL) {
perror("Cannot open file");
return((CLERROR *)NULL);
}
while(fgets(errorstr, 80, pfp) != NULL)
for(i = 0; i 0) {
item_len = strlen((char *)&str[*pos]);
item = (char *)malloc(item_len + 1);
memset(item, 0, item_len + 1);
memcpy(item, &str[*pos], item_len);
}
else return((char *)NULL);
return(item);
}
注意:上面的ut_readtext()函数取自《Unix/linux下curses库开发指南》一书,如需使用,请尊重愿作者。
6.显示抬头信息
抬头信息显示在headwin中,至于显示那些信息由个人而定.
7.另外一些用得上的函数
在curses环境中,希望调用一个shell,然后返回,这需要一些特殊处理,有两个例程来处理这个情况 reset_shell_mode()和reset_prog_mode() 它们两个重新设置终端到shell模式和curses模式.
int ut_runcommand(s)
char *s;
{
int status, pid, w;
void (*istat)(), (*qstat)();
if ( (pid = fork()) == 0 ) {
ut_closeall();
reset_shell_mode();
if ( !s ) signal(SIGINT, SIG_DFL);
execl("/bin/sh", "sh", s? "-c": 0, s, 0);
_exit(127);
}
istat = (void (*)())signal(SIGINT, SIG_IGN);
qstat = (void (*)())signal(SIGQUIT, SIG_IGN);
while( (w = wait(&status)) != pid && w != -1 );
if ( w == -1 ) status = -1;
signal(SIGINT, istat); signal(SIGQUIT, qstat);
reset_prog_mode();
return(status);
}
此函数在子进程中引用一个shell来执行指定的命令s,并且处理信号SIGINT和SIGQUIT.
其中的ut_closeall()关闭0 1 2文件.
读出并显示文本文件:
int cl_dispfile(win, y, x, txtname)
WINDOW *win;
int y, x;
char *txtname;
{
int i, j;
long int ch;
int ret;
FILE *txtfp;
if((txtfp = fopen(txtname, "rb")) == NULL) {
cl_disperror(msgwin, ut_geterror("E001"), A_REVERSE);
return(0);
}
cl_dispprompt(ut_getprompt("P003"));
i = x;
j = y;
while((ch = fgetc(txtfp)) != EOF) {
if(i++ > COLS) {
i = x; ++j;
}
switch(ch) {
case 0x0a :
++j;
i = x;
mvwaddch(win, j, i, ch);
break;
default :
mvwaddch(win, j, i, ch);
break;
}
if(j == FORM_EROW - 1) {
loop1:
wmove(win, FORM_EROW - 1, 0);
ret = wgetch(win);
switch(ret) {
case 0x0e :
case '\r' :
cl_fullregion(win, y, x,
FORM_EROW - FORM_SROW - 2, COLS, ' ');
wrefresh(win);
j = y;
i = x;
break;
case 'q' :
case 0x1b :
cl_fullregion(win, y, x,
FORM_EROW - FORM_SROW - 2, COLS, 0);
wrefresh(win);
return(1);
default :
beep();
goto loop1;
}
}
}
wrefresh(win);
return(1);
}
这是个简单版本,你还可以扩充,如指定显示宽度 高度等,还可以控制上翻下翻,显示文件行数当前行等等信息.这个函数中注意两点:一是ch要定义成long int 或 int,不要定义成char,这样才可以显示中文字符,还有就是TAB字符的处理.
8.结束工作
在curses结束时,要退出curses模式,使终端回到shell模式,并且将输入/输出还原.
void cl_endwindow()
{
if(workwin) delwin(workwin);
if(headwin) delwin(headwin);
if(msgwin) delwin(msgwin);
if(slk_you)
slk_clear();
clear();
endwin();
}
其实直接用endwin()也可以正常退出,但是我们已经建立了三个窗口,并且有可能使用了软标签,所以还做了一些清理工作.
(未完待续)
本文来自ChinaUnix博客,如果查看原文请点:http://blog.chinaunix.net/u/31/showart_508065.html |
|