Chinaunix首页 | 论坛 | 博客
  • 博客访问: 908760
  • 博文数量: 139
  • 博客积分: 10016
  • 博客等级: 上将
  • 技术积分: 932
  • 用 户 组: 普通用户
  • 注册时间: 2005-07-31 02:15
文章存档

2008年(19)

2007年(73)

2006年(46)

2005年(1)

我的朋友

分类: LINUX

2007-02-10 20:16:09

      在上期为您介绍完了 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,"Press 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); /* 设定另一视窗大小 */ 
         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 函式库的使用方法, 相信同学对撰写这类的 
    程式应该不再陌生. 所谓『戏法人人会变, 巧妙各有不同』. 知道了基本函式 
    的呼叫方法, 能不能写出实用的程式, 就靠各位的巧思和创造力了. 
阅读(1147) | 评论(0) | 转发(0) |
给主人留下些什么吧!~~