发新话题
打印

UNIX 萤幕导向程式的发展利器 - curses (二)

UNIX 萤幕导向程式的发展利器 - curses (二)

  UNIX 萤幕导向程式的发展利器 - curses (二)




???????? UNIX 萤幕导向程式的发展利器 - curses (二)


?????????????????????????????校园网路策进会
?????????????????????????????会长??林建宏


???在上期为您介绍完了 curses.h 函式库的一些基本函式呼叫後在, 在本期里
??, 我们将继续为您介绍 curses 有关多视窗处理的函式. 有了这些函式, 我们
??可以在程式里同时处理多个不同的视窗.?如 joe 编辑器内我们可将萤幕切割
??成好几个小萤幕, 并且可以在这些不同的萤幕间做切换并编辑不同的档案, 这
??就是多视处理的应用. 另外, 有关 POP-UP 视窗的制作, 以及视窗的卷动, 在
??本文里, 我们将以简单的例子, 告诉您这些功能是如何做到的. 关於一些较基
??本函式的用法, 我们将不再特别介绍. 如果您尚未熟悉 curses 基本函式使用
??方法, 请参阅上一期 (80 期 ) 通讯.


?■ 视窗的建立

??视窗的建立, 以 newwin() 这个函式来完成.?同时, 需宣告此视窗为 WINDOW
??结构变数.

??WINDOW *newwin(lines,colums,start_y,start_x);

?? WINDOW *win;
?? win=newwin(10,20,0,0);

??如此, 将以 (0,0) 为原点, 取一个 10 列 20 行的矩形为一新的视窗.?今後
??我们只要呼叫 win 这个变数, 就可以对这新视窗做处理.

?? 如: wmove(win,3,2);


?■ 多视窗处理函式的格式

??这一类函式和一般的基本函式极为类似, 几乎每一个基本函式都有一个对应的
??视窗处理函式.?一般将 'w' 加在函式的里头作为区别, 'w' 乃 'window' 之
??意. 另外, 因为可同时处理多个视窗, 在呼叫使用时, 需特别指定欲处理的视
??窗. 当然, 如果您指定对 stdscr 做处理, 由於是对标准输出入萤幕处理, 其
??作用将相当於一般基本的函式.

?? 如:

???wmove(win,y,x)?? 即对 win 这个视窗做 move() 动作.
???wmove(stdscr,y,x)?相当於 move(y,x)

??介绍一些较重要的函式

??wmove(win,y,x)
??touchwin(win)
??wrefresh(win)
??mvwaddstr(win,y,x,str)
??wattron(attr)
??delwin(win)
??subwin(win,ny,nx,y,x)

??其他函式多和基本函式互为对应, 故不全部列出, 详细名称可参考 curses
??的 online manual.

?■ 视窗内的座标系

??视窗内的座标系, 将以此视窗的起始点为新原点, 并以其相对位置作为新的
??座标. 举例来说

??win=newwin(10,20,5,5);
??wmove(win,2,3);

??将以 (5,5) 为新原点,?y 方向移动 2 单位, x 方向移动 3 单位. 因此实际
??上, 游标将移动至 y=7 x=8 的位置上.


?■ POP-UP 视窗的建立

??利用 curses 所提供的视窗处理函式, 我们可以做出像?ONLINE HELP 的 POP
??-UP 画面. 当按下某键後, 一个新的视窗将像 " 跳 " 出来一般覆盖原来的画
??面. 当关掉此视窗後, 又不会影响到原来被覆盖的画面.


??下面的例子, 我们及模拟 ONLINE HELP 的形式, 当按下 'h' 键时, 视窗即出现


? #include

? main()
??{
?? int ch,x,y;
?? WINDOW *win;

?? initscr();? ←┐
?? cbreak;????│ 启动 curses 模式
?? noecho();???│
?? nonl();???←┘

?? win=newwin(4,30,LINES/2-3, COLS/2-15);/* 建立一个新视窗, 其中LINES,COLS *.
?? box(win,'|','-');?????????? /* 为 curses 内定值, 即萤幕行/列数*.
?? mvwaddstr(win,1,4,"This is another screen");
?? mvwaddstr(win,2,2,"ress anykey to continue..");

?? for (y=0;y???for (x=0;x????mvprintw(y,x,"@");

???for(;;) {
??? refresh();
??? ch=getch();
??? switch(ch) {
???? case 'q':????????/* 按 'q' 键离开 */
????????? endwin();
????????? exit(0);

???? case '\t':???????/* 按 [TAB] 键 呼叫另一视窗? */
????? touchwin(win);????/* wrefresh() 前需 touchwin() */
????? wrefresh(win);
????? getch();???????/* 按任意键关闭视窗 */
????? touchwin(stdscr);
????? break;

???? default:break;
????}
???}
??}


? 执行结果:

???┌────────────────────────────┐
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???└────────────────────────────┘
?????????? ↑ 原来画面被 '@' 填满, 按下[TAB]键後
?????????? ↓ 出现 POP-UP 画面.
???┌────────────────────────────┐
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@+----------------------------+@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@|? This is another screen? |@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@| Press anykey to continue.. |@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@+----------------------------+@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???│ @@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@@ │
???└────────────────────────────┘


?■ 视窗的卷动

??视窗的卷动, 掖Q用来配合视窗的处理, 当我们持续对视窗输出直到视窗的游
??标移动至最後一列时, 如果我们再输出一列或是输出一个换行字元时, 视窗可
??整个往上卷动一行. 这对我们撰写一个编辑程式时, 是尤其重要的, 一个画面
??无法卷动的编辑器, 势必无法处理超过一个萤幕大小的档案.

??视窗的卷动是预设为关闭的, 并以 scrollok() 来控制开闭.

??scrollok(win,TRUE);??开启
??scrollok(win,FALSE);? 关闭


??下面的例子因为不断地输出 0,1,2.. 故将以一个 40 * 10 的视窗不停的卷动

???#include

???main()
??? {
???? int i;
???? WINDOW *scrwin,*boxwin;

???? initscr();?? ←┐
???? cbreak;?????│ 启动 curses 模式
???? noecho();????│
???? nonl();????←┘

???? scrwin=newwin(10,40,LINES/2-6,COLS/2-25); /* 设定另一礸﹞j小 */
???? boxwin=newwin(12,42,LINES/2-7,COLS/2-26); /* 设定外框视窗大小 */

???? scrollok(scrwin,TRUE);?/* 开启视窗卷动功能 */

???? box(boxwin,'|','-');
???? refresh();
???? wrefresh(boxwin);

???? for (i=0;;++i)???? /* 不断地在视窗内输出 0-8 的数字,使视窗卷动 */
????? {
????? wprintw(scrwin,"%d",i%9);
????? wrefresh(scrwin);
????? }
????}


???执行结果:
??????┌──────────────────────┐
??????│???? +----------------------+????? │
??????│???? |3456780123456780123412| ↑ 视?? │
??????│???? |3456780123456780123456| │ 窗?? │
??????│???? |7801234567801234567801| │ 不?? │
??????│???? |2345678012345678012345| │ 停?? │
??????│???? |6780123456780123456780| │ 往?? │
??????│???? |1234567801234567801234| │ 上?? │
??????│???? |5678012345678012345678| │ 卷?? │
??????│???? |0123456780123456780123| │ 动?? │
??????│???? +----------------------+????? │
??????│??????????????????????│
??????└──────────────────────┘


?■ 范例 - 模拟 joe 分割画面同时编辑两个档案

?? 在下面的例子里, 我们应用了多视窗处理的函式, 改良上回介绍的编辑器,
?? 在这个程式里, 我们可以同时编辑两个画面, 并以 [ESC] 做不同视窗间的
?? 切换. 同时, 按下 [TAB] 键, 会出现 POP-UP 的 ONLINE HELP.


? #include

? void initial();

? main()
? {
?? WINDOW *win[2],*curwin,*helpwin;
?? int nowwin;
?? int x,y;
?? int i;
?? int ch;

?? initial();

?? win[0]=newwin(LINES/2-1,COLS-1,0,0);??? /* 设定两个视窗的大小*/
?? win[1]=newwin(LINES/2-1,COLS-1,LINES/2,0);

?? helpwin=newwin(3,30,2,COLS/2-15 );????/* ONLINE HELP 的大小 */
?? box(helpwin,'|','-');
?? mvwaddstr(helpwin,0,10,"ONLINE HELP");??/* ONLINE HELP 的内容 */
?? mvwaddstr(helpwin,1,4,"Hit any key to continue..");

?? for (i=0;i??? mvaddch(LINES/2-1,i,'-');

?? nowwin=0;?????????????/* 先指定游标在第一视窗 */
?? curwin=win[nowwin];
?? getyx(curwin,y,x);
?? move(0,0);
?? refresh();

?? refresh();

?? do {
??? ch=getch();
??? switch(ch) {

???? case KEY_UP: --y;?????? /* 判断是否"↑"键被按下??? */
???????????break;
???? case KEY_DOWN: ++y;????? /* 判断是否"↓"键被按下??? */
???????????break;
???? case KEY_RIGHT: ++x;?????/* 判断是否"→"键被按下??? */
???????????break;
???? case KEY_LEFT: --x;????? /* 判断是否"←"键被按下??? */
???????????break;
???? case '\r':??????????/* 判断是否 ENTER 键被按下??*/
????????? ++y;
????????? x=0;
????????? break;
???? case '\t':??????????/* 判断是否 TAB 键被按下???*/
????????? touchwin(helpwin);
????????? wrefresh(helpwin);?/* 呼叫 ONLINE HELP */
????????? getch();
????????? touchwin(win[1-nowwin]);?/* 重画第一,二视窗 */
????????? wrefresh(win[1-nowwin]);
????????? touchwin(curwin);
????????? wrefresh(curwin);
????????? break;
???? case 127:???????????/* 判断是否 BACKSPACE 键被按下 */
????????? wmove(curwin,y,--x);/* delete 一个字元??????*/
????????? waddch(curwin,' ');
????????? break;

???? case 27 : nowwin=1-nowwin;?? /* [ESC] 键切换视窗 */
????????? curwin=win[nowwin];
????????? getyx(curwin,y,x);
????????? break;
???? default:
????????? waddch(curwin,ch);
????????? x++;
????????? break;
??? }
??? wmove(curwin,y,x);
??? wrefresh(curwin);
?? } while(1);
? }

? void initial()
? {
?? initscr();?????????←┐
?? cbreak();?????????? │ 启动 curses 模式
?? nonl();??????????? │
?? noecho();????????? ←┘
?? intrflush(stdscr,FALSE);
?? keypad(stdscr,TRUE);
?? refresh();
? }


??执行结果:

????? ┌─────────────────────────────┐
????? │??screen1??????????????????????? │
?? ┌→?│???? this is screen 1, you can press [ESC] to???? │
?以 │??│?? switch between screen 1 and screen 2.????????│
[ESC]│??│?????????????????????????????│
?切 │??│?????????????????????????????│
?换 │??│----------------------------------------------------------│
?游 │??│?? screen 2?????????????????????? │
?标 │??│?????????????????????????????│
?位 └→?│????_ (游标)?????????????????????│
?置??? │?????????????????????????????│
????? └─────────────────────────────┘
????????????????? ↑ 按下[TAB] 键,出现 ONLINE HELP
????????????????? ↓
????? ┌─────────────────────────────┐
????? │??screen1??????????????????????? │
????? │???? this is screen 1, you can press [ESC] to???? │
????? │?? switch+---------ONLINE HELP--------+???????? │
????? │????? |? Hit any key to continue..|???????? │
????? │????? +----------------------------+???????? │
????? │----------------------------------------------------------│
????? │?? screen 2?????????????????????? │
????? │?????????????????????????????│
????? │?????????????????????????????│
????? │?????????????????????????????│
????? └─────────────────────────────┘
????????????????? ↑ 按任意键, ONLINE HELP 关闭
????????????????? ↓
????? ┌─────────────────────────────┐
????? │??screen1??????????????????????? │
????? │???? this is screen 1, you can press [ESC] to???? │
????? │?? switch between screen 1 and screen 2.????????│
????? │?????????????????????????????│
????? │?????????????????????????????│
????? │----------------------------------------------------------│
????? │?? screen 2?????????????????????? │
????? │?????????????????????????????│
????? │????_ (游标)?????????????????????│
????? │?????????????????????????????│
????? └─────────────────────────────┘

■ 结语

??我们以连续两期来介绍 curses.h 函式库的使用方法, 相信同学对撰写这类的
??程式应该不再陌生. 所谓『戏法人人会变, 巧妙各有不同』. 知道了基本函式
??的呼叫方法, 能不能写出实用的程式, 就靠各位的巧思和创造力了.

??有任何问题建议, 欢迎 E-mail 至?ljh@CCCA.NCTU.edu.tw , 谢谢 !
Never say die !!! 高调做事,低调做人!! 暂负此心,只为不负此生; 暂负一时,只为不负一世。
发新话题