• GNU-ncurses库简介



    前言

    ncurses是一个管理应用程序在字符终端显示的函数库。它提供了移动光标,建立窗口,产生颜色,处理鼠标操作等功能。
    ncurses提供的是字符用户界面,而非图形用户界面


    一、安装与使用

    Ubuntu下执行如下命令

    sudo apt-get install libncurses5-dev
    
    • 1

    在编译时需要加上-lncurses选项

    在运行编译好的二进制文件时也要安装ncurses库

    二、ncurses库基本用法

    #include 
    
    int main()
    {
        initscr();  // 初始化,进入ncurses模式,创建虚拟屏幕
        printw("hello world");  // 在虚拟屏幕上光标位置打印 hello world
        refresh();  // 将虚拟屏幕上的内容写到显示器上,并刷新
        getchar();  // libc
        endwin();   // 推出ncurses模式
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    2.1 initscr()

    将终端屏幕初始化为curses模式,该函数初始化了curses系统并且为当前屏幕(“stdscr”)和相关的数据结构分配内存。

    2.2 refresh()

    printw函数用于向stdscr虚拟屏幕缓冲区写入数据,refresh函数负责将stdscr缓冲区中的数据显示在屏幕上。refresh只核查窗口和数据中变动的部分。

    2.3 endwin()

    释放了curses子系统和相关数据结构占用的内存,使得能够正常返回控制台模式,否则程序推出后终端显示会变得异常。

    三、初始化

    初始化后curses session的模式及功能包括:terminal mode, color mode, mouse mode 等

    3.1 raw(), cbreak()

    一般而言,终端驱动程序会缓冲用户输入的字符,直到遇到换行符或者回车符后,这些字符才可以被使用。raw和cbreak可以禁止行缓冲(line buffering):row可以处理ctrl+z, ctrl+c等控制字符,将其传送至程序而不产生终端信号;cbreak则不会这样处理.

    3.2 echo() noecho()

    noecho() 禁止输入的字符出现在屏幕上

    3.3 keypad()

    为stdscr激活功能键 keypad(stdscr, true)

    3.4 int halfdelay(int)

    以 0.1 s 为单位等待用户输入,若在规定的时间内没有输入则返回#define ERR -1

    #include 
    #include 
    #include 
    
    int main()
    {
        initscr();   // 开始curses模式
        int ch;
        curs_set(false);  // 关闭光标显示
        raw();  // 禁用输入缓冲
        keypad(stdscr, TRUE);  // 没有它当按下Fn时程序似乎不正常
        noecho();   // 当执行getch函数时关闭键盘回显
        // 向缓冲区stdscr中写数据
        printw("Type any character to seee it in bold\n");
        // 用法同getchar,但又有区别,可尝试换成getchar会怎样
        // curses库中getch与getchar用法相似,但如果用getchar函数会出现的显示上的问题
        // 这个问题有待进一步探究
        ch = getch();  // 如果没有raw()函数必须按下enter时才将字符传给程序
        for (int i = 1; i<=12; ++i) {
        	// 如果没有keypad将不会执行这条语句
            if (ch == KEY_F(i)) {
                printw("F%d Key pressed", i);
                // 如果没有noecho一些控制字符将被打印到屏幕上
                goto conti_exe;
            }
        }
        printw("The pressed key is ");
        attron(A_BOLD);  // 看名知意
        printw("%c", ch);
        attroff(A_BOLD);
        conti_exe:
        refresh();  // 将stdscr的内容显示到屏幕
        getch();    // 等待用户输入
        endwin();  // 结束curses模式
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36

    四、窗口机制简介

    printw(string);  // 在窗口stdscr的当前坐标输出string
    refresh();
    
    // w+  指定窗口显示
    wprintw(win, string);  // 在win上写string
    wrefresh(win);  // 刷新窗口win
    
    // mv+ 在指定位置打印
    mvprintw(y, x, string);  在stdscr的(y, x)处写string
    mvwprintw(win, y, x, string);  // 在win的(y, x)处写string 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10

    五、输出函数

    addch()系列:将单一的字符打印到屏幕上,可以附加字符修饰参数的一类函数
    printw()系列:类似printf格式化输出
    addstr()系列:打印字符串

    addch( ch | A_BOLD | A_UNDERLINE);

    attrset(), 不可叠加文本属性
    attron(), attroff() 可叠加文本属性

    ACS_ 开头的宏可用于绘制一些简单的表格、线条等

    vwprintw()和vprintf()相似,用于打印变量表中所对应的变量(没用过)

    指定窗口指定位置指定窗口+位置
    addchwaddchmvaddchmvwaddch
    addstrwaddstrmvaddstrmvwaddstr
    printwwprintwmvprintwmvwprintw

    getmaxyx

        initscr();
        curs_set(false);
        raw();
        keypad(stdscr, TRUE);
        noecho();
        
        char mesg[] = "Just a string";
        int row, col;
        getmaxyx(stdscr, row, col);
        mvprintw(row/2, (col-strlen(mesg))/2, "%s", mesg);
        mvprintw(row-2, 0, "This screen has %d rows and %d columns\n", row, col);
        printw("Try resizing your window(if possible and then run this prog)");
    
        refresh();
        getch();
        endwin();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16

    六、输入函数

    getch() 系列:读取一个字符
    scanw()系列:按照格式化读取输入
    getstr() 系列:读取字符串

    scanwwscanwmvscanwmvwscanw
    getchwgetchmvgetchmvwgetch
        char mesg[] = "Just a string";
        char str[80];
        int row, col;
        getmaxyx(stdscr, row, col);
        mvprintw(LINES/2, (COLS-strlen(mesg))/2, "%s", mesg);
        getstr(str);
        mvprintw(LINES-2, 0, "You ENtered:%s\n", str);
    
        printw("row:%d, col:%d, LINES:%d", row, col, LINES);
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    七、输出修饰

    #include 
    #include 
    #include 
    #include 
    #include 
    
    int main(int argc, char* argv[])
    {
    
        
    //
        int ch, prev;
        FILE *fp;
        int goto_prev = false, y, x; /* sdfg*/
        if (argc != 2)
        {
            printf("error");
            exit(1);
        }
        fp = fopen(argv[1], "r");
        if (fp == NULL)
        {
            perror("Connot open inputfile");
            exit(1);
        }
    
        initscr();
        curs_set(false);
        raw();
        keypad(stdscr, TRUE);
        noecho();
    
    
        prev = EOF;
        while ((ch = fgetc(fp)) != EOF)
        {
            if (prev == '/' && ch == '*')
            {
                attron(A_BOLD);
                goto_prev = true;
            }
            if (goto_prev == true)
            {
                getyx(stdscr, y, x);
                move(y, x -1);
                printw("%c%c", '/', ch);
                ch = 'a';
                goto_prev = false;
            }
            else
            {
                printw("%c", ch);
            }
            refresh();
            if (prev == '*' && ch == '/')
            {
                attroff(A_BOLD);
            }
            prev = ch;
        }
        
        
    ///
        refresh();
        getch();
        endwin();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    说明
    A_NORMAL普通字符
    说明
    attrset会覆盖之前的设置
    attron会追加
    attroff只会关闭特定修饰
    standend()等价于attrset(A_NORMAL)
    attr_get()获得当前窗口修饰属性设置及背景、文字颜色
    需要在设置的修饰之后才能使用
    attr_类函数
    wattr_类函数
    chgat()
    wchgat()
    mvchgat()
    mvwchgat()
        start_color();
        init_pair(1, COLOR_CYAN, COLOR_BLACK);
        printw("A Big string which i didn't care to type fully");
        mvchgat(0, 10, 4, A_BLINK, 1, NULL);
        //  第三个参数表示从光标开始的向后几个字符,-1代表整行, 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    八、窗口机制

    声明说明
    WINDOW * newwin (h, w, y, x);创建窗口结构体
    int delwin(WINDOW*);释放窗口资源
    int wborder(win, L, R, U, D, 左上, 右上,左下,右下)绘制边框
    int mvhline(y, x, char, num)draw h line
    int mvvline(y, x, char, num)draw v line

    假象stdscr有个二维数组存储窗口中的内容,newwin是在这个二维数组中划分
    在原有的stdscr窗口中创建新的窗口,

    #include 
    #include 
    #include 
    #include 
    #include 
    
    WINDOW* create_nwin(int h, int w, int y, int x)
    {
        WINDOW* local_win;
        local_win = newwin(h, w, y, x);
        // box(local_win, 0, 0);
        wborder(local_win,'*','*','*','*','#','#','#','#');
        wrefresh(local_win);
        return local_win;
    }
    
    void del_win(WINDOW* local)
    {
        wborder(local,' ',' ',' ',' ',' ',' ',' ',' ');
        wrefresh(local);
        delwin(local);
    }
    
    int main(int argc, char* argv[])
    {
        initscr();
        curs_set(false);
        raw();
        keypad(stdscr, TRUE);
        noecho();
        
    //
        
        WINDOW* myw;
        int w = 10, h = 7, x = (COLS-w)/2, y = (LINES-h)/2;
        int ch;
        printw("Press F1 to exit");
        refresh();
        myw = create_nwin(h, w, y, x);
        while ((ch = getch()) != KEY_F(1))
        {
            switch (ch)
            {
            case KEY_LEFT:
                del_win(myw);
                myw = create_nwin(h, w, y, --x);
                break;
            case KEY_RIGHT:
                del_win(myw);
                myw = create_nwin(h, w, y, ++x);
                break;
            case KEY_UP:
                del_win(myw);
                myw = create_nwin(h, w, --y, x);
                break;
            case KEY_DOWN:
                del_win(myw);
                myw = create_nwin(h, w, ++y, x);
                break;
            
            default:
                break;
            }
        }
        
    ///
        // getch();
        endwin();
    
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70

    九、颜色系统

    声明说明
    bool has_colors(void)检测当前终端是否支持颜色显示
    int start_color()启动颜色机制,初始化相关内容
    init_pair(颜色号,前景色,背景色)定义颜色对,定义好颜色对后就可以将号传给COLOR_PAIR(n)宏, attron(COLOR_PAIR(n))
    init_color(COLOR_RED颜色名,R, G, B);改变某个颜色的RGB值, rgb的值从0到1000
    color_content()
    pair_content()
    查看当前颜色设置
    颜色
    COLOR_BLACK0
    COLOR_MAGENTA5洋红色
    COLOR_CYAN6蓝绿,青色
    COLOR_

    easy menu

    #include 
    #include 
    
    #define WIDTH 30
    #define HEIGHT 10
    
    int startx = 0;
    int starty = 0;
    char* choices[] = {
        "File",
        "Edit",
        "Selection",
        "View"
    };
    int n_choices = sizeof(choices) / sizeof(char*);
    
    void print_menu(WINDOW* menu_win, int highlight)
    {
        int x = 2, y = 2;
        box(menu_win, 0, 0);
        for (int i = 0; i < n_choices; ++i)
        {
            if (highlight == i + 1)
            {
                wattron(menu_win, A_REVERSE);
                mvwprintw(menu_win, y, x, "%s", choices[i]);
                wattroff(menu_win, A_REVERSE);
            }
            else
            {
                mvwprintw(menu_win, y, x, "%s", choices[i]);
            }
            ++y;
        }
        wrefresh(menu_win);
    }
    
    void main()
    {
        WINDOW* menu_win;
        int highlight = 1;
        int choice = 0;
        int c;
        initscr();
        curs_set(false);
        clear();
        noecho();
        raw();
        startx = (80 - WIDTH) / 2;
        starty = (24 - HEIGHT) / 2;
        menu_win = newwin(HEIGHT, WIDTH, starty, startx);
        keypad(menu_win, TRUE);
        mvprintw(0, 0, "Use");
        refresh();
        print_menu(menu_win, highlight);
        while (1)
        {
            c = wgetch(menu_win);
            switch (c)
            {
            case KEY_UP:
                if (highlight == 1)
                {
                    highlight = n_choices;
                }
                else
                {
                    --highlight;
                }
                break;
            case KEY_DOWN:
                if (highlight == n_choices)
                {
                    highlight = 1;
                }
                else
                {
                    ++highlight;
                }
                break;
            case 10:
                choice = highlight;
                break;
            default:
                mvprintw(24, 0, "press is %3d hopelly can be printed as %c", c, c);
                refresh();
                break;
            }
            print_menu(menu_win, highlight);
            if (choice != 0) break;
        }
        mvprintw(23, 0, "You cho %d with choice string %s\n", choice, choices[choice-1]);
        clrtoeol();
        refresh();
        endwin();
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97

  • 相关阅读:
    【css案例】
    浅谈建筑能耗智能监测平台发展现状及未来趋势
    [附源码]java毕业设计大学生就业信息检索系统
    【微信小程序】小程序代码基本组成结构
    在断更的日子里,我想了很多... ...
    分布式事务提交慢的一次总结和思考
    S32K148_CAN驱动(裸机开发)
    3D技术在数字藏品中的应用
    JAVA小说小程序系统是怎样开发的
    java毕业生设计中医药科普网站计算机源码+系统+mysql+调试部署+lw
  • 原文地址:https://blog.csdn.net/surfaceyan/article/details/133085113