<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      (超詳細) ncurses 庫使用介紹: 實現終端 GUI

      這次 ENGG1340 課程的 group project 是設計并實現一個 text-base game,作為終端上運行的 text-base game,有一個出彩的 GUI 肯定是一個加分項!

      在未老師的介紹下,我知道了有 <ncurses.h> 庫這么一個神奇的東西;最重要的是,雖然它不屬于 C++ 標準庫,但是在學校 server 里居然默認下載好了 (可見其出名的功能強大)
      據說很多熱門的終端程序,例如 Vim,SL 都用到了 ncurses

      花了一個下午學習了一下用法,在這里簡單的總結一下,并且附上一些簡單 GUI 組成的實例

      Installation

      官方 release 網址在這里

      在終端上輸入命令 sudo apt-get install libncurses5 進行安裝


      Compilation

      所有使用了 <ncurses.h> 庫的程序,在編譯時需要添加參數 -l ncurses 使編譯器鏈接到 ncurses 庫

      例: g++ -o test test.cpp -lncurses


      初始化窗口對象

      使用 initscr() 初始化標準窗口對象 stdscr (WINDOW 類)

      初始化過后,我們接下來將與該窗口對象進行交互: std::cin/out, scan/printf 等標準輸入輸出將失效


      返回常規終端模式

      當使用完 ncurses,想回到常規終端模式時,使用 endwin() 來關閉窗口

      通常在程序退出前調用 endwin()


      輸入/輸出

      在調用 endwin() 之前,標準輸入輸出將失效

      想要與初始化后的窗口對象交互,我們需要使用 ncurses 庫提供的輸入/輸出函數

      #include <ncurses.h>
      
      int scanw(char* format, ...);   // 用法與 scanf 相同
      int printw(char* format, ...);  // 用法與 printf 相同
      int getch(void);                // 用法同 getchar, 有阻礙程序繼續的功能
      

      由于 gp 中使用了很多 string,我自定義了兩個接口用來處理 string 類型的輸入輸出

      #include <string>
      #include <ncurses.h>
      
      string instr() {
        char s[1024];
        scanw("%[^\n]", s);   // 這里對標的是 getline, 回車時結束讀入
        return string(s);
      }
      void outstr(string s) {
        printw("%s", s.c_str());
      }
      

      在指定位置輸出

      在 ncurses 模式中,我們可以通過 mv() 函數輕松控制光標的位置,從而實現在終端的指定位置輸出

      mv(x, y) 將光標移動到當前窗口的第 \(x\) 行第 \(y\) 列 (行列均從 \(0\) 開始),且接下來輸出的內容都將從該位置開始

      以下實例將在從屏幕中央開始 (注意,是開始而不是位于) 輸出 "Hello World!"

      #include <ncurses.h>
      
      ...
      int scrLine, scrCol;
      getmaxyx(stdscr, scrLine, scrCol);       // 獲取標準屏幕的行/列數
      move(scrLine / 2 - 1, scrCol / 2 - 1);   // 將光標移至屏幕中央
      printw("Hello World!");
      ...
      

      移動光標和輸出可以在同一個函數 mvprintw() 中完成: 例如上例程序可寫成 mvprintw(scrLine / 2 - 1, scrCol / 2 - 1, "Hello World!")

      在輸出完畢后,使用 refresh() 進行刷新,將輸出顯示到當前屏幕上


      新窗口/子窗口

      創建新窗口/子窗口

      在未指定的情況下,initscr() 初始化的窗口是標準屏幕 stdscr

      而有時我們需要多個窗口;通過創建新窗口 (newwin) 或子窗口 (subwin)

      創建新窗口時,其會被分配一個新的內存;而子窗口與其父窗口共用內存

      WINDOW* newwin(int line, int col, int x, int y);                 // 創建新窗口
      WINDOW* submin(WINDOW* parent, int line, int col, int x, int y); // 創建子窗口,其父窗口為 parent
      

      刪除新窗口/子窗口

      使用 del(win) 刪除窗口 win,即,釋放其所占用的內存

      • 刪除窗口 win 并不代表 屏幕上 win 輸出的內容會消失,因此在刪除之前調用 wclear(win)wrefresh(win) 進行清屏

      • 不要刪除 ncurses 的默認窗口 stdscr, 結束它使用 endwin() 即可

      非標準窗口的交互操作

      超級簡單易懂,之前我們介紹的所有對 stdscr 的函數,加上前綴 w,再添加對應窗口的指針作為參數就得到了與非標準窗口交互的函數

      例如:printw() 對應 wprintw(win), refresh() 對應 wrefresh(win), mvprinrw() 對應 mvwprintw(win) (這個位置稍有不同)

      WINDOW* win = newwin(30, 30, 0, 0);
      wmvprintw(win, 1, 1, "Joker");     // 注意,這里的 (1, 1) 是對于窗口 win 的相對位置,而不是對于 stdscr 的絕對位置
      wrefresh(win);                     // 進行刷新,使內容顯示到屏幕上
      or
      WINDOW* sub = subwin(stdscr, 30, 30, 0, 0);    // sub 是標準窗口的子窗口
      wmvprintw(sub, 1, 1, "Skull"); 
      touchwin(stdscr);                              // 由于 sub 與標準窗口共用內存,我們用 touchwin() 函數標記標準窗口被修改即可,而非使用 wrefresh()
      

      子窗口與父窗口

      當我們使用 wmove() 或其他對非標準窗口的交互函數對子窗口進行操作時,父窗口 (或其他子窗口) 輸出的內容會暫時消失

      解決方法是:在 touchwin(fascr) 過后,再對父窗口進行刷新

      wrefresh(father_scr)refresh() (當父窗口是標準窗口時)

      WINDOW* upwin = subwin(stdscr, scrLine / 2, scrCol, 0, 0);
      WINDOW* downwin = subwin(stdscr, scrLine / 2, scrCol, scrLine / 2, 0);
      
      box(upwin, '|', '+');
      box(downwin, '|', '+');
      touchwin(stdscr);
      
      wmove(downwin, 1, 1);
      // refresh();
      int a;
      wscanw(downwin, "%d", &a);
      
      getch();
      

      當未加 refresh() 時,upwin 窗口的輸出內容 (即 box 繪出的邊框) 將不會顯示

      只有將對父窗口重新刷新 refresh() 之后,所有的輸出內容才會顯示


      窗口轉儲

      這在實現 text-base game 中是一個很實用的功能,它可以用來實現場景的切換,與讀/存檔功能

      例如,"開始" 界面可以進入 "游戲" 界面,但從 "游戲" 界面返回時,由于屏幕已經被 "游戲" 界面所在窗口覆蓋,我們需要重新加載 "開始" 界面

      此時,利用窗口的轉儲,我們可以直接恢復之前的界面

      標準窗口轉儲

      標準窗口 stdscr 可以利用下面的兩個函數進行存儲與讀取:

      int scr_dump(const char*);    // 參數是當前目錄下文件的名稱: scr_dump 將會把標準窗口中的內容存儲到對應名稱的文件中
                                    // 若當前目錄下沒有該名稱的文件,將會創建一個
      int scr_restore(const char*); // scr_restore 函數將會讀取對應文件中存儲的內容,并將其載入到標準窗口中
      

      以下是一個簡單的例程 (gp 中的界面轉換可以以此為基礎)

      printw("Main Menu\n");          // 標準窗口作為主界面 main menu
      refresh();
      scr_dump("a");                  // 儲存當前標準窗口的內容
      
      getch();
      WINDOW* win = newwin(scrLine, scrCol, 0, 0);
      wprintw("Game Started!\n");     // 一個與標準窗口相同大小的新窗口 win 作為游戲界面
      wrefresh(win);
      
      getch();
      wclear(win);
      wrefresh(win);                  // 游戲界面結束,將屏幕清空
      delwin(win);                    // 釋放游戲界面所在窗口 win 的內存
      
      // getch();
      scr_restore("a");               // 返回主界面 main menu, 使用 scr_restore() 恢復
      refresh();
      

      若有時我們需要暫時退出 ncurses 模式,回到行緩沖模式,我們可以儲存當前標準窗口的內容后再退出

      (或使用 def_prog_mode()reset_prog_mode() 函數,由于 gp 中可能不會用到,這里不多介紹)

      非標準窗口轉儲

      當然,除了標準窗口 stdscr,其他任何我們新創建的窗口都可以進行轉儲

      使用以下的兩個函數:

      int putwin(WINDOW*, FILE*);     // 存
      int getwin(WINDOW*, FILE*);     // 讀
                                      // 注意,這兩個函數的文件參數不是文件名 (字符串),而是文件指針
      

      滾屏操作

      在行緩沖模式中,若輸出的內容超過了終端的 bottom line,將會自動滾屏 (舊的輸出將會向上滾動,為新的輸出留位置)

      我以為 ncurses 中的窗口默認滾屏,結果當輸出超出屏幕時,反而向右溢出了

      我翻了好久的庫文檔,終于找到了對應的函數 (這里)

      int scrollok(WIN*, bool);        // 在 WIN 指針指向的窗口中開啟 (true)/關閉 (false) 滾屏
      setscrreg(int x, int line);      // 在 scrollok 開啟后,可以在窗口中設立一個滾屏區,在該區域內有滾屏
                                       // 滾屏區從第 [x] 行開始,共占 [line] 行
      

      顏色設置

      有時候我們希望改變窗口的背景與文本顏色, ncurses 庫對此也提供了支持

      在使用之前,我們先初始化顏色設置

      bool has_color(void);            // 返回該環境是否支持顏色設置
      int start_color(void);           // 初始化顏色設置
      

      start_color() 成功調用后,一系列的常量將會產生,例 COLOR (支持的顏色數量),COLOR_BLACK (黑色), COLOR_WHITE...

      我們使用 init_pair() 函數來創建 背景-文本 的顏色對,并用 attron() 函數激活

      接下來,直到 attroff() 關閉之前,所有輸出的 背景-文本 都將是指定的顏色對

      init_pair(1, COLOR_BLACK, COLOR_WHITE);  // [黑]底[白]字為第 1 個顏色對
                                               // 注意,每一種顏色對的編號必須是不同的!
      attron(COLOR_PAIR(1));                   // 傳入之前定義的顏色對作為參數 (以編號表示),開啟顏色設置
      printw("Black background white text\n");
      attroff(COLOR_PAIR(1));                  // 關閉顏色設置,恢復默認
                                               // 此處也可以直接 attron 其他顏色對,而無需先 attroff
      

      對非標準窗口的操作使用 wattron(WINDOW*, ...)wattroff(WINDOW*, ...)


      其他輸出文本效果

      attron()attroff() 不僅可以用來設定顏色,還能夠實現許多輸出文本效果

      這些效果通過一系列常量來代表: A_BLINK, A_DIM, A_UNDERLINE

      例如: attron(A_BLINK),那么在 attronoff(A_BLINK) 之前輸出的文本都將閃爍顯示

      這些效果的復合 (甚至與顏色的復合) 可以通過常量間的或 | 運算簡單的實現 (這與 windows 對終端文本顏色的操作很相似)

      例如 attron(A_BLINK | A_UNDERLINE) 代表文本閃爍且加下劃線顯示

      這里附上 ncurses 提供的所有輸出文本效果常量

      A_NORMAL       // 普通字符輸出(不加亮顯示)
      A_STANDOUT     // 終端字符最亮
      A_UNDERLINE    // 下劃線
      A_REVERSE      // 字符反白顯示
      A_BLINK        // 閃動顯示
      A_DIM          // 半亮顯示
      A_BOLD         // 加亮加粗
      A_PROTECT      // 保護模式
      A_INVIS        // 空白顯示模式
      A_ALTCHARSET   // 字符交替
      A_CHARTEXT     // 字符掩蓋
      COLOR_PAIR(n)  // 前景、背景色設置
      

      Reference

      1. Debian ncurses manpage
      2. tiga-Unix/Linux下的Curses庫開發指南——第三章curses庫窗口 (這好像也是轉載的,但是翻譯的很好,也很全)
      3. KeBlog-ncurses (Kewth NB)
      4. ztq-ncurses庫 常用函數及基本使用 (有一個通過子窗口實現分屏的程序,gp 的時候可以借鑒,修改一下參數)
      5. ncurses 輸出修飾 (包含了 ncurses 提供的一系列 attr 前綴函數,對輸出進行修飾,很有用)
      posted @ 2023-04-14 14:55  四季夏目天下第一  閱讀(12079)  評論(0)    收藏  舉報
      主站蜘蛛池模板: 男女性高爱潮免费网站| 丰满少妇特黄一区二区三区| 丁香五月婷激情综合第九色| 欧美午夜精品久久久久久浪潮 | 日本一区二区中文字幕久久| 蜜臀av日韩精品一区二区| 免费无码av片在线观看播放| 人妻一区二区三区三区| 日韩精品一区二区三区蜜臀| 欧美乱妇高清无乱码免费| 精品国模一区二区三区| 国内精品自国内精品自久久| av在线播放观看国产| 亚洲欧洲日韩精品在线| 亚洲婷婷综合色高清在线| 国内精品免费久久久久电影院97 | 精品视频一区二区| 国产精品自拍实拍在线看| 免费国产一级 片内射老| 欧美成人h亚洲综合在线观看| 午夜片神马影院福利| 九九热在线免费播放视频| 熟女一区二区中文字幕| 欧美成人一卡二卡三卡四卡| 好男人社区在线www| 一区二区三区国产亚洲网站| 欧美性猛交xxxx免费看| 无码精品一区二区三区在线| 91高清免费国产自产拍| 欧美一本大道香蕉综合视频| 亚洲色大成网站WWW永久网站| 亚洲精品中文综合第一页| 日韩在线视频线观看一区| 国产一级片内射在线视频| 久久一本人碰碰人碰| 久久夜色精品久久噜噜亚| 欧美一本大道香蕉综合视频| 中文字幕人妻av第一区| 人人澡人人透人人爽| 一区二区三区四区五区色| 韩国精品久久久久久无码|