C指针原理(34)-Ncurses-文本终端的图形

下面使用getwin和putwin完成对窗口内容的保存,而不是对整个屏幕,同时修正程序的几个小错误:

1、下面的操作提示在多次操作后会出现混乱。

2、退出后,endwin结束窗口,并且退出curses模式。

dp@dp:~/cursestest % cat a.c

#include 

#include 

#include 

//code by [email protected]

//date:2014/1/17

int isExist(char *filename)

{

         return (access(filename, 0) == 0);

}

int main(int argc, char *argv[])

{

        MEVENT event;

        setlocale(LC_ALL,"");

        initscr();

        clear();

        noecho();

        cbreak();

        if(has_colors() == FALSE)

        {

        endwin();

        printf("你的终端不支持色彩!\n");

        return (1);

        }

        start_color(); /*启动color 机制*/

        mvprintw(3,COLS/2-10,"简单编辑器-仅限于单个屏幕的编辑");

        mvprintw(4,COLS/2-15,"【F9读保存内容,F10存盘,F11退出,F12删除整行】");

        refresh();

        init_pair(1, COLOR_GREEN, COLOR_BLACK);

        WINDOW *win1;

        int width=COLS-14;

        int height=LINES-14;

        int x,y;

        win1=newwin(height,width,7,7);//新窗口(行,列,begin_y,begin_x)

        keypad(wi

n1,TRUE);

    wattron(win1,COLOR_PAIR(1));

    box(win1,ACS_VLINE,ACS_HLINE);

    wrefresh(win1);

    getyx(win1,y,x);

    ++y;++x;

    mmask_t oldmousemask;

    int ans=0;

    FILE *fp2=NULL;

    FILE *fp1=NULL;

    mousemask(ALL_MOUSE_EVENTS, &oldmousemask);

    while(1){

            int c=mvwgetch(win1,y,x);

            switch(c)

            {       case KEY_MOUSE:

                    if(getmouse(&event) == OK)

                    {       /* When the user clicks left mouse button */

                            if(event.bstate & BUTTON1_PRESSED)

                            {

                                            y=event.y-7;x=event.x-7;

                                            wmove(win1,y,x);

                            }

                    }

                    break;

                    case KEY_BACKSPACE:

                            --x;

                            if (x<1){

                                    --y;x=width-2;

                            }

                            if (y<1){

                                    y=height-2;

                            }

                            mvwprintw(win1,y,x," ");

                            break;

                    case KEY_RIGHT:

                            ++x;

                            if (x>=width-1) {

                                    ++y;

                                    x=1;

                            }

                            break;

                    case KEY_LEFT: --x;

                            if (x<1){

                                    --y;

                                    x=width-2;

                            }

                            break;

                    case KEY_UP:

                            --y;

                            if (y<1){

                                    y=height-2;

                            }

                            break;

                    case KEY_DOWN:

                            ++y;

                            if (y>=height-1){

                                    y=1;

                            }

                            break;

                    case 10:

                            ++y;

                            if (y>=height-1){

                                    y=1;

                            }

                            break;

                    case KEY_F(11):

                            //退出

                            mvprintw(LINES-3,2,"                     ");

                            mvprintw(LINES-3,2,"退出编辑器吗?     ");

                            mvprintw(LINES-2,2,"    ");

                            mvprintw(LINES-1,2,"     \n");

                            refresh();

                            ans=getch();

                            if (ans=='Y' ||ans=='y')

                            {

                                    mvprintw(LINES-2,2,"是\n");

                                    refresh();

                                    wattroff(win1,COLOR_PAIR(1));

                                    mousemask(oldmousemask,NULL);

                                    delwin(win1);

                                    endwin();

                                    return 0;

                            }else

                                    mvprintw(LINES-2,2,"否\n");

                                    refresh();

                            break;

                    case KEY_F(10):

                            //存盘

                            mvprintw(LINES-3,2,"                     ");

                            mvprintw(LINES-3,2,"保存当前内容吗?     ");

                            mvprintw(LINES-2,2,"    ");

                            mvprintw(LINES-1,2,"     \n");

                            refresh();

                            ans=getch();

                            if (ans=='Y' ||ans=='y')

                            {

                                    mvprintw(LINES-3,2,"                     ");

                                    fp1 = fopen("myet.dat","wb");

                                    if (fp1!=NULL){

                                            int jg= putwin(win1,fp1);

                                            fclose(fp1);

                                            if (jg==OK)  mvprintw(LINES-1,2,"保存成功!\n");

                                    }

                                    mvprintw(LINES-3,2,"保存当前内容吗?     ");

                                    mvprintw(LINES-2,2,"是\n");

                                    refresh();

                            }else

                                    mvprintw(LINES-2,2,"否\n");

                                    refresh();

                            break;

                    case KEY_F(9):

                            //读取存盘

                            mvprintw(LINES-3,2,"                    ");

                            mvprintw(LINES-3,2,"读取保存内容吗?    ");

                            mvprintw(LINES-2,2,"    ");

                            mvprintw(LINES-1,2,"     \n");

                            refresh();

                            ans=getch();

                            if (ans=='Y' ||ans=='y')

                            {

                                    if (isExist("myet.dat")) {

                                    fp2 = fopen("myet.dat","rb");

                                    if (fp2!=NULL){

                                            WINDOW *newwin=getwin(fp2);

                                            if (newwin!=NULL) {

                                                    delwin(win1);

                                                    win1=newwin;

                                                    wrefresh(win1);

                                                    mvprintw(LINES-1,2,"读取成功!\n");

                                            }

                                            fclose(fp2);

                                    }

                                    }

                                    mvprintw(LINES-3,2,"读取保存内容吗?    ");

                                    mvprintw(LINES-2,2,"是\n");

                                    refresh();

                            }else

                                    mvprintw(LINES-2,2,"否\n");

                                    refresh();

                            break;

                    case KEY_F(12):

                            //删除某行

                            wdeleteln(win1);

                            winsertln(win1);

                            box(win1,ACS_VLINE,ACS_HLINE);

                            break;

                    case KEY_DC:

                            //删除某字符

                            mvwprintw(win1,y,x," ");

                            break;

                    default:

                            mvwprintw(win1,y,x,"%c",c);

                            ++x;

                            if (x>=width-1){

                                    ++y;

                                    x=1;

                            }

                            if (y>=height-1){

                                    y=1;

                            }

                            wrefresh(win1);

            }

        }

}

执行

dp@dp:~/cursestest % gcc -lncursesw a.c -o mytest

dp@dp:~/cursestest % ./mytest
面板库(Panel Library)能方便得管理面板:

  1. 使用newwin()函数创建一个窗口,它将添加到面板里。

  2. 创建面板(利用所创建的窗口)并将面板依据用户指定的可见顺序压进栈。调用

new_panel()函数即可创建该面板。

  1. 调用update_panels()函数就可将面板按正确的顺序写入虚拟屏幕,调用doupdate()函

数就能让面板显示出来。

  1. show_panel(), hide_panel(), move_panel()等函数分别用来对面板进行显示、隐藏、移

动等操作时,可以使用panel_hidden()和panel_window()这两个辅助函数。你也可以

使用用户指针来存储面板的数据,set_panel_userptr() 和panel_userptr()函数分别用

来设置和取得一个面板的用户指针。

  1. 当一个面板使用完毕后,用del_panel()函数就可删除指定的面板。

下面是一个例子

dp@dp:~/cursestest % cat x.c

#include 

int main()

{

WINDOW *my_wins[3];

PANEL *my_panels[3];

int lines = 10, cols = 40, y = 2, x = 4, i;

initscr();

cbreak();

noecho();

/* 为每个面板创建窗口*/

my_wins[0] = newwin(lines, cols, y, x);

my_wins[1] = newwin(lines, cols, y + 1, x + 5);

my_wins[2] = newwin(lines, cols, y + 2, x + 10);

/* 为窗口添加创建边框以便你能看到面板的效果*/

for(i = 0; i < 3; +++i)

box(my_wins[i], 0, 0);

/* 按自底向上的顺序,为每一个面板关联一个窗口*/

my_panels[0] = new_panel(my_wins[0]);

/* 把面板0 压进栈, 叠放顺序: stdscr0

*/

my_panels[1] = new_panel(my_wins[1]);

/* 把面板1 压进栈, 叠放顺序: stdscr01

*/

my_panels[2] = new_panel(my_wins[2]);

/* 把面板2 压进栈, 叠放顺序: stdscr012*/

/* 更新栈的顺序。把面板2 置于栈顶*/

update_panels();

/* 在屏幕上显示*/

doupdate();

getch();

endwin();

}

dp@dp:~/cursestest % gcc -lncursesw -lpanel x.c -o mytest

dp@dp:~/cursestest % ./mytest

屏幕上显示了三个窗口,每个窗口都是一个面板,每个面板关联一个窗口。如下图所示:

然后看看隐藏和显示面板

dp@dp:~/cursestest % cat x.c

#include 

int main()

{

WINDOW *my_wins[3];

PANEL *my_panels[3];

int lines = 10, cols = 40, y = 2, x = 4, i;

int ch;

initscr();

cbreak();

noecho();

/* 为每个面板创建窗口*/

my_wins[0] = newwin(lines, cols, y, x);

my_wins[1] = newwin(lines, cols, y + 1, x + 5);

my_wins[2] = newwin(lines, cols, y + 2, x + 10);

/* 为窗口添加创建边框以便你能看到面板的效果*/

for(i = 0; i < 3; +++i)

box(my_wins[i], 0, 0);

/* 按自底向上的顺序,为每一个面板关联一个窗口*/

my_panels[0] = new_panel(my_wins[0]);

/* 把面板0 压进栈, 叠放顺序: stdscr0

*/

my_panels[1] = new_panel(my_wins[1]);

/* 把面板1 压进栈, 叠放顺序: stdscr01

*/

my_panels[2] = new_panel(my_wins[2]);

/* 把面板2 压进栈, 叠放顺序: stdscr012*/

/* 更新栈的顺序。把面板2 置于栈顶*/

update_panels();

/* 在屏幕上显示*/

doupdate();

//q退出,按1-3键显示和隐藏对应的面板

int isshow[3]={1,1,1};

while((ch = getch()) !='q')

{ switch(ch)

{

case '1':

if ((++isshow[0])%2) show_panel(my_panels[0]);

else hide_panel (my_panels[0]);

break;

case '2':

if ((++isshow[1])%2) show_panel(my_panels[1]);

else hide_panel (my_panels[1]);

break;

case '3':

if ((++isshow[2])%2) show_panel(my_panels[2]);

else hide_panel (my_panels[2]);

break;

}

update_panels();

doupdate();

}

getch();

endwin();

}

执行后

dp@dp:~/cursestest % gcc -lncursesw -lpanel x.c -o mytest

dp@dp:~/cursestest % ./mytest

比如把2号面板隐藏,效果如下
调用mousemask( )这个函数来激活你想要接收的鼠标事件。

mousemask( mmask_t newmask, / 你想要监听的鼠标事件掩码/

mmask_t oldmask ) / 旧版本使用的鼠标事件掩码*/

主要事件如下:(一般来说,左键为1 号,右键为2 号)

BUTTON1_PRESSED 鼠标1 号键按下

BUTTON1_RELEASED 鼠标1 号键释放

BUTTON1_CLICKED 鼠标1 号键单击

BUTTON1_DOUBLE_CLICKED 鼠标1 号键双击

BUTTON1_TRIPLE_CLICKED 鼠标1 号键三击

BUTTON2_PRESSED 鼠标2 号键按下

BUTTON2_RELEASED 鼠标2 号键释放

BUTTON2_CLICKED 鼠标2 号键单击

BUTTON2_DOUBLE_CLICKED 鼠标2 号键双击

BUTTON2_TRIPLE_CLICKED 鼠标2 号键三击

BUTTON3_PRESSED 鼠标3 号键按下

BUTTON3_RELEASED 鼠标3 号键释放

BUTTON3_CLICKED 鼠标3 号键单击

BUTTON3_DOUBLE_CLICKED 鼠标3 号键双击

BUTTON3_TRIPLE_CLICKED 鼠标3 号键三击

BUTTON4_PRESSED 鼠标4 号键按下

BUTTON4_RELEASED 鼠标4 号键释放

BUTTON4_CLICKED 鼠标4 号键单击

BUTTON4_DOUBLE_CLICKED 鼠标4 号键双击

BUTTON4_TRIPLE_CLICKED 鼠标4 号键三击

BUTTON_SHIFT 在鼠标事件发生时,伴随Shift 键按下

BUTTON_CTRL 在鼠标事件发生时,伴随Ctrl 键按下

BUTTON_ALT 在鼠标事件发生时,伴随Alt 键按下

ALL_MOUSE_EVENTS 报告所有的鼠标事件

REPORT_MOUSE_POSITION 报告鼠标移动位置

getmouse()函数将这个事件返回一个相应的指针。这个指针结构是这样的:

typedef struct

{

short id; / ID 用来辨别不同的设备/

int x, y, z; / 事件发生的坐标/

mmask_t bstate; / 鼠标按键状态/

}

Bstate 是我们关注的最主要变量,它返回了当前鼠标按键的状态。下面的这段代码可以捕捉鼠标左键按下:

if(event.bstate & BUTTON1_PRESSED)

我们在上面的编辑器中加上鼠标左键定位。

dp@dp:~/cursestest % cat a.c

#include 

#include 

#include 



int main(int argc, char *argv[])

{

MEVENT event;

setlocale(LC_ALL,"");

initscr();

clear();

noecho();

cbreak();

if(has_colors() == FALSE)

{ 

endwin();

printf("你的终端不支持色彩!\n");

return (1);

}

start_color(); /启动color 机制/

mvprintw(5,COLS/2-10,"简单编辑器-仅限于单个屏幕的编辑");

refresh();

init_pair(1, COLOR_GREEN, COLOR_BLACK);

WINDOW *win1;  

int width=COLS-14;

        int height=LINES-14;

        int x,y;

        win1=newwin(height,width,7,7);//新窗口(行,列,begin_y,begin_x)

keypad(win1,TRUE);

        wattron(win1,COLOR_PAIR(1));

        box(win1,ACS_VLINE,ACS_HLINE);

wrefresh(win1);

getyx(win1,y,x);

++y;++x;

mmask_t oldmousemask;

mousemask(ALL_MOUSE_EVENTS, &oldmousemask);

while(1){

int c=mvwgetch(win1,y,x);

switch(c)

{ case KEY_MOUSE:

if(getmouse(&event) == OK)

{ / When the user clicks left mouse button /

if(event.bstate & BUTTON1_PRESSED)

{

y=event.y-7;x=event.x-7;

wmove(win1,y,x);

}

}

break;

case KEY_RIGHT:

++x;

if (x>=width-1) {

++y;

x=1;

}

break;

case KEY_LEFT: --x;

if (x<1){

--y;

x=width-2;

}

break;

case KEY_UP:

        --y;

if (y<1){

y=height-2;

}

break;

case KEY_DOWN:

        ++y;

if (y>=height-1){

y=1;

}

break;

case 10:

        ++y;

if (y>=height-1){

y=1;

}

break;

case KEY_F(1):

        //退出

mvprintw(LINES-3,2,"退出编辑器吗?");

mvprintw(LINES-2,2,"    ");

refresh();

int ans=getch();

if (ans=='Y' ||ans=='y')

{

mvprintw(LINES-2,2,"是\n");

refresh();

return 0;

}else

mvprintw(LINES-2,2,"否\n");

refresh();

break;

case KEY_F(12):

        //删除某行

wdeleteln(win1);

winsertln(win1);

         box(win1,ACS_VLINE,ACS_HLINE);

case KEY_DC:

        //删除某字符

                 mvwprintw(win1,y,x," ");

break;

default:

                 mvwprintw(win1,y,x,"%c",c);

++x;

if (x>=width-1){

         ++y;

x=1;

}

if (y>=height-1){

y=1;

}

wrefresh(win1);

}

}

        wattroff(win1,COLOR_PAIR(1));

endwin();

mousemask(oldmousemask,NULL);

return 0;

}

执行

dp@dp:~/cursestest % gcc -lncursesw a.c -o mytest

dp@dp:~/cursestest % ./mytest

scr_dump() 函数可以把当前屏幕的内容存入指定文件,即以文件名作为函数的参数,而通过 scr_restore()函数调用屏幕数据文件来恢复屏幕。它们的函数调用方式为:

scr_dump(const char *file)

scr_restore(const char *file)

getwin()函数用来将窗口内容存储到一个指定的文件中。 putwin() 函数则调用相应的文件来恢复窗口。

它们的函数调用方式为:

getwin(FILE * filep)

putwin(WINDOW win, FILE filep)

我们先利用scr_dump()与scr_restore()函数,实现将编辑器的内容存盘与读取,但是它会把整个屏幕保存下来。

设定F9读取,F10存盘,同时修改退出为F11,并加入对退格键的支持。

dp@dp:~/cursestest % cat a.c

#include 

#include 

#include 



int isExist(char *filename)

{

         return (access(filename, 0) == 0);

}

int main(int argc, char *argv[])

{

        MEVENT event;

        setlocale(LC_ALL,"");

        initscr();

        clear();

        noecho();

        cbreak();

        if(has_colors() == FALSE)

        {

        endwin();

        printf("你的终端不支持色彩!\n");

        return (1);

        }

        start_color(); /启动color 机制/

        mvprintw(3,COLS/2-10,"简单编辑器-仅限于单个屏幕的编辑");

        mvprintw(4,COLS/2-15,"【F9读保存内容,F10存盘,F11退出,F12删除整行】");

        refresh();

        init_pair(1, COLOR_GREEN, COLOR_BLACK);

        WINDOW *win1;

        int width=COLS-14;

        int height=LINES-14;

        int x,y;

        win1=newwin(height,width,7,7);//新窗口(行,列,begin_y,begin_x)

        keypad(win1,TRUE);

        wattron(win1,COLOR_PAIR(1));

        box(win1,ACS_VLINE,ACS_HLINE);

        wrefresh(win1);

        getyx(win1,y,x);

        ++y;++x;

        mmask_t oldmousemask;

        int ans=0;

        mousemask(ALL_MOUSE_EVENTS, &oldmousemask);

        while(1){

                int c=mvwgetch(win1,y,x);

                switch(c)

                {       case KEY_MOUSE:

                        if(getmouse(&event) == OK)

                        {       / When the user clicks left mouse button /

                                if(event.bstate & BUTTON1_PRESSED)

                                {

                                                y=event.y-7;x=event.x-7;

                                                wmove(win1,y,x);

                                }

                        }

                        break;

                        case KEY_BACKSPACE:

                                --x;

                                if (x<1){

                                        --y;x=width-2;

                                }

                                if (y<1){

                                        y=height-2;

                                }

                                mvwprintw(win1,y,x," ");

                                break;

                        case KEY_RIGHT:

                                ++x;

                                if (x>=width-1) {

                                        ++y;

                                        x=1;

                                }

                                break;

                        case KEY_LEFT: --x;

                                if (x<1){

                                        --y;

                                        x=width-2;

                                }

                                break;

                        case KEY_UP:

                                --y;

                                if (y<1){

                                        y=height-2;

                                }

                                break;

                        case KEY_DOWN:

                                ++y;

                                if (y>=height-1){

                                        y=1;

                                }

                                break;

                        case 10:

                                ++y;

                                if (y>=height-1){

                                        y=1;

                                }

                                break;

                        case KEY_F(11):

                                //退出

                                mvprintw(LINES-3,2,"                     ");

                                mvprintw(LINES-3,2,"退出编辑器吗?     ");

                                mvprintw(LINES-2,2,"    ");

                                refresh();

                                ans=getch();

                                if (ans=='Y' ||ans=='y')

                                {

                                        mvprintw(LINES-2,2,"是\n");

                                        refresh();

                                        return 0;

                                }else

                                        mvprintw(LINES-2,2,"否\n");

                                        refresh();

                                break;

                        case KEY_F(10):

                                //存盘

                                mvprintw(LINES-3,2,"                     ");

                                mvprintw(LINES-3,2,"保存当前内容吗?     ");

                                mvprintw(LINES-2,2,"    ");

                                refresh();

                                ans=getch();

                                if (ans=='Y' ||ans=='y')

                                {

                                        mvprintw(LINES-3,2,"                     ");

                                        scr_dump("myedit.dat");

                                        mvprintw(LINES-3,2,"保存当前内容吗?     ");

                                        mvprintw(LINES-2,2,"是\n");

                                        refresh();

                                }else

                                        mvprintw(LINES-2,2,"否\n");

                                        refresh();

                                break;

                        case KEY_F(9):

                                //读取存盘

                                mvprintw(LINES-3,2,"                    ");

                                mvprintw(LINES-3,2,"读取保存内容吗?    ");

                                mvprintw(LINES-2,2,"    ");

                                refresh();

                                ans=getch();

                                if (ans=='Y' ||ans=='y')

                                {

                                        if (isExist("myedit.dat")) scr_restore("myedit.dat");

                                        mvprintw(LINES-3,2,"读取保存内容吗?    ");

                                        mvprintw(LINES-2,2,"是\n");

                                        refresh();

                                }else

                                        mvprintw(LINES-2,2,"否\n");

                                        refresh();

                                break;

                        case KEY_F(12):

                                //删除某行

                                wdeleteln(win1);

                                winsertln(win1);

                                box(win1,ACS_VLINE,ACS_HLINE);

                                break;

                        case KEY_DC:

                                //删除某字符

                                mvwprintw(win1,y,x," ");

                                break;

                        default:

                                mvwprintw(win1,y,x,"%c",c);

                                ++x;

                                if (x>=width-1){

                                        ++y;

                                        x=1;

                                }

                                if (y>=height-1){

                                        y=1;

                                }

                                wrefresh(win1);

                }

        }

        wattroff(win1,COLOR_PAIR(1));

        endwin();

        mousemask(oldmousemask,NULL);

        return 0;

}

执行

dp@dp:~/cursestest % gcc -lncursesw a.c -o mytest

dp@dp:~/cursestest % ./mytest

你可能感兴趣的:(设计与架构)