Summary: Ncurses is a dynamic library that provides function key definition (shortcut keys), screen rendering, and graphic interaction functions based on text terminals.
What is ncurses?Do you want your program to have a color interface? Ncurses is a dynamic library that provides text terminal window-based functions. ncurses can:
- As long as you like, you can use the entire Screen
- Create and manage a window
- Use 8 different colors
- Provide mouse support for your program
- Use the function key on the keyboard
Ncurses can run on any UNIX system that complies with the ANSI/POSIX standard. In addition, ncurses can detect terminal attributes from the system database and automatically adjust them, provides a terminal-free interface. therefore, ncurses can work well on different system platforms and terminals. The MC tool set is a good example written with ncurses, and the core configuration interface of the system on the terminal is also written with ncurses. Below are their: Where can I download it?Ncurses is developed based on GNU/Linux. Visit http://www.gnu.org/software/ncurses/to provide the latest updates and detailed information for relevant links. Basic knowledgeTo be able to use the ncurses library, you must set curses in your source program. h Includes (include), and must be connected to it during compilation. in GCC, you can use the parameter-lcurses for compilation. When using ncurses, you need to understand its basic data structure. it has a window structure, which is easily known from the name. It is used to describe the form you created. All functions in the ncurse Library contain a window pointer parameter. The most commonly used component in ncurses is a form. even if you do not create your own form, the current screen will consider it as your own form. like the stdout file descriptor provided by the standard input/output system to the screen (assuming there is no pipeline redirection), ncurses provides a window pointer stdscr for the same purpose. in addition to stdscr, ncurses also defines a window pointer curscr. like stdscr describing the current screen, curscr describes the screen defined in the current library. What is the difference between them? "Continue reading this question. To use ncurses functions and variables in your program, you must first call the initscr function (initialization), which allocates memory for some variables such as stdscr and curscr, make the ncurses library ready for use. In other words, all ncurses must be behind initscr. similarly, you should use endwin to release all ncurses memory after using ncurses. after using endwin, you cannot use any ncurses function, unless you call the initscr function again. Between initscr and endwin, do not use the function output result of the standard input/output Library to the screen. Otherwise, the screen will be messy by your output, this is not the expected result. when ncurses is active, use its own function to output the result to the screen. before calling initscr or endwin, you can use it as needed. Refresh screen: refreshThe window structure does not always keep the same height width and position in the form, but will keep the content in the form. when you write data to the form, the content in the form is changed, but it does not mean that the screen is displayed immediately. to update the screen content, you must call the refresh or wrefres function. The difference between stdscr and curscr is introduced here. curscr stores the content of the current screen. after calling the ncurse output function, stdscr and curscr may have different contents, to make stdscr consistent with curscr after the last screen content change, you must use the refresh function. in other words, refresh is the only function that processes curscr. do not confuse curscr and stdscr. You should update the content in curscr In the refresh function. Refresh has a mechanism to update the screen as quickly as possible. When calling refresh, it only updates the rows with changed content in the form, which saves the CPU processing time, prevent programs from writing the same information to the screen .) this mechanism is why ncurses functions and standard input/output functions at the same time cause misplacement of screen content. when calling the ncurses output function, it sets a flag to let refresh know which line has changed. however, this result is not generated when you call the standard input/output function. Refresh and wrefresh actually do the same thing. wrefresh requires a window pointer parameter, which only refreshes the content of the form. refresh () is equivalent to wrefresh (stdscr ). as I will mention later, like wrefresh, many ncursers functions have many macro functions defined for stdscr. Define a new formNext we will talk about the subwin and newwin functions that can define the new form. they all need a parameter to define the height, width, and position in the upper left corner of the new form, and return a window pointer to point to the form. you can use it as the wrefresh parameter or some other functions I will talk about. You may ask: "If they do the same thing, why do they need two functions? ", You are right. There are some minor differences between them. subwin creates a subform of a form that inherits all attributes of the parent form. however, if the value of these attributes is changed in the child form, it will not affect the parent form. In addition, there are some relationships between the parent form and the child form. the content in the parent form and child form will be shared with each other and affect each other. in other words, the characters in the overlapping areas of the parent window and child form will be changed by any form. if the parent form writes data to this area, the area in the child form also changes, and vice versa. Unlike subwin, newwin creates a unique form. such forms do not share any text data with other forms before they have their child forms. the advantage of using subwin is that you can easily share character data with less memory. however, if you are worried that the form data will affect each other, you should use newwin. You can create multiple sub-forms. Each sub-form can have its own sub-forms, but remember that the character content of the form is shared by more than two forms. After you call the defined form, you can use the delwin function to delete the form. We recommend that you use man pages to obtain the detailed parameters of these functions. Write Data to and read data from the formWe talked about stdscr, curscr, and refreshing the screen and defining a new form. But how do we write data to a form? How do we read data from a form? Like some functions in the standard input/output library, we use printw to replace the printf output content, scanw to replace scanf to accept the input, and addch to replace putc or putchar, use getch to replace GETC or getchar. they use the same method. They only have different names. Similarly, addstr can be used to write a string to the form, while getstr can be used to read a string from the form. all these functions start with a "W" letter, followed by the word of the function. to operate on the Content of another form, the first parameter must be the Windows structure pointer of the form, for example, printw (...) and wprintw (stdscr ,...) is the same, just like refresh () and wrefresh (stdscr. If you want to write a detailed description of these functions, this article will become very long. man pages is a good choice to get their descriptions, prototype, return value, or other information. we recommend that you check a function you are using against man pages. they provide detailed and useful information. in the last section of this article, I provide a sample program, which can be used as a guide for using the ncurses function. Physical pointer and logical pointerAfter writing data and reading data from the form, we need to explain that the physical pointer and logical pointer are a common pointer, which has only one, and from the other, logical pointers belong to the ncurses form. Each form has only one physical pointer, but they can have multiple logical pointers. When the form is to be written and read out, the logical Pointer Points to the area in the form to be operated. therefore, by moving the logical pointer, you can write data to any position in the form at any time. this is the difference with the advantages of the standard input/output library. The function that moves the logical pointer is move or another function that you can easily guess is wmove. move is a macro function of wmove, which is specially used to process stdscr. Another thing to be confirmed is the collaboration between the physical pointer and the logical pointer. The location of the physical pointer will be invalid after a program is written, however, we can use the _ leave flag of the window structure to locate it. if the _ leave flag is set, after the write operation is complete, the logical pointer will be moved to the area where the physical Pointer Points to the last write in the form. if the _ leave bit is not set, after the write operation is complete, the physical pointer will return to the first character write position of the logical pointer pointing to the form. the _ leave flag is controlled by the leaveok function. The function that moves the physical pointer is mvcur. Unlike other functions, mvcur takes effect immediately without waiting for the refresh action. if you want to hide the physical pointer, you can use the curs_set function and man pages for detailed information. Some macro functions simplify the above functions, such as moving and writing. you can get more explanations on the man pages Pages of functions such as addch, addstr, printw, getch, getstr, and scanw. Clear formAfter we finish writing content to the form, how can we clear the form, line, and character? In ncurses, clearing means filling the entire area, line, or whole form with blank characters. the functions I will introduce below will fill the necessary areas with spaces to achieve our screen clearing purpose. First, let's talk about functions that can clearly understand characters and rows. delch and wdelch can delete the characters pointed to by the form logical pointer. The next character and the characters until the end of the line will be moved to the left position. deleteln and wdeleteln can delete rows pointed to by logical pointers and move the rows up and down. Clrteol and wclrtoeol can clear all characters starting from the right of the logical pointer to the end of the row. clrtbot and wclrtobot first clear all characters starting from the right of the logical pointer location to the end of the row, and then delete all the following rows. In addition, some functions can clear the entire screen and form. there are two ways to clear the entire screen. the first is to fill all areas of the screen with blank characters, and then call the refresh function. another method is to use a fixed terminal to control character clearing. the first method is slow because it needs to overwrite the current screen. the second method can quickly clear the entire screen content. Erase and werase Replace the text characters of the form with blank characters. The screen content will be cleared after the next call to refresh. however, if the form needs to clear the entire screen, this would be a relatively benzene method. you can use the first method described above. when the form needs to be cleared as wide as a screen, you can use the function described below to complete your task very well. Before using other functions, we will discuss the _ clear flag. if this flag is set, it will exist in the window structure. when calling it, it uses refresh to send control code to the terminal. Refresh checks whether the width of the form is the width of the screen (use the _ fullwin flag ). if yes, it will use the built-in terminal method to refresh the screen, it will write text characters in addition to blank characters to the screen, this is a very fast screen cleaning method. why do I use the built-in terminal method to clear the screen only when the width of the form is equal to the screen width? This is because the control Terminal code not only clears the form itself, but also clears the current screen. _ clear flag is controlled by the clearok function. The clear and wclear functions are used to clear the form content with the same width as the screen. in fact, these functions are equivalent to using werase and clearok. first, it fills in the text characters of the form with blank characters. then, set the _ clear flag. If the form width is the same as the screen width, use the built-in terminal method to clear the screen. If the form width is different, fill all the areas of the form with blank characters and refresh the screen. All in all, if you know that the width of the form is the same as that of the screen width, you can use clear or wclear, which is very fast. if the form width is not the same as the screen width, wclear and werase are used without any difference. Use colorThe colors you see on the screen are actually color pairs, because each area has a background color and a foreground color. using ncurses to display colors means you define your own color pairs and write these color pairs to the form. Just as the ncurses function must call initscr first, start_color must be called first to initialize the pigment. the function you use to define your own color pair is init_pair. When you use it to define a color pair, it will be associated with the first parameter you set in the function. in the program, no matter when you need to use this color pair, you only need to use color_pair to call this parameter. In addition to defining color pairs, you must also use functions to ensure that different color pairs are used for writing. attron and wattron can meet your requirements. using these functions will write data to the corresponding screen with the color you selected until the attroff or wattroff function is called. The bkgd and wbkgd functions can change the color pairs of the entire form. When called, it will change the foreground color and background color of all areas of the form. that is to say, before the next refresh action, all the areas on the form will be overwritten with a new color pair. Use the man pages function just mentioned to obtain detailed color information and information. Border of the formYou can provide a nice border for the form in your program. There is a box macro function in the library to do this for you. Unlike other functions, no wbox function. box requires a window pointer as a parameter. You can easily get detailed help on the man pages page of box. Note that setting borders for a form only writes some characters in the corresponding border area of the form. if you write some data in the border area, the border will be interrupted. the solution is to create a child form in the original form, place the original form into the border, and use the child form in it as the required input data form. Function keyTo use the function key, you must set the _ use_keypad flag in the form that we need to accept the input. keypad is a function that can set the _ use_keypad value. After you set _ use_keypad, you can use the function key (shortcut key) of the keyboard, just like a normal input. Here, if you want to use getch as an example to simply accept data input, you need to assign the data to the integer variable (INT) instead of the character type (char ). this is because the integer variable can hold more function keys than the primary type. you do not need to know the value of these function keys. You only need to use the macro names defined in the database. The man page of getch contains a list of these values. ExampleWe will analyze a very simple and practical program in the future. in this program, ncurses will be used to define the menu, and one of the options in the menu will be proved to be optional. the interesting side of this program is that the ncurses form is used to achieve the menu effect. you can see the screen below. The program starts to be the same as the normal one, including a header file. Then we define the ASCII value of the Enter key and escape key. #include <curses.h>#include <stdlib.h>#define ENTER 10#define ESCAPE 27 When the program is running, the following functions will be called. it first calls the initscr initialization pointer and then calls start_color to display the color. the color pairs used in the entire program will be defined later. calling curs_set (0) will block the physical pointer. noecho () displays the input on the terminated keyboard on the screen. you can use the noecho function to control the characters entered on the keyboard. Only the expected characters are allowed to be displayed. echo () will block this effect. the next function keypad sets the function keys (shortcut keys) that can be used to accept the keyboard in stdscr. We need to define F1, F2, and the moving optical key in the subsequent program. void init_curses(){ initscr(); start_color(); init_pair(1,COLOR_WHITE,COLOR_BLUE); init_pair(2,COLOR_BLUE,COLOR_WHITE); init_pair(3,COLOR_RED,COLOR_WHITE); curs_set(0); noecho(); keypad(stdscr,TRUE);} The function defined below defines a menu bar that is displayed at the top of the screen. You can see the main program below. It looks like it is just a line at the top of the screen, in fact, it is actually a subform of the stdscr form, which has only one row. the following program uses the pointer to the child form as its parameter. First, it changes its background color and then defines the menu word. We use waddstr to define the menu word. it should be noted that wattron calls another different color pair (serial number 3) to replace the default color pair (serial number 2 ). remember that the color pair 2 was set to the default color by wbkgd at the beginning. the wattroff function allows us to switch to the default color pair status. void draw_menubar(WINDOW *menubar){ wbkgd(menubar,COLOR_PAIR(2)); waddstr(menubar,"Menu1"); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F1)"); wattroff(menubar,COLOR_PAIR(3)); wmove(menubar,0,20); waddstr(menubar,"Menu2"); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F2)"); wattroff(menubar,COLOR_PAIR(3));} The next function displays the menu displayed when the F1 or F2 key is pressed, defining a white background form with the same color as the menu bar on the blue background, we do not want this new window to be overwritten by words displayed on the background color. they should stay there until the menu is closed. this is why the menu form cannot be defined as a subform of stdscr. as mentioned below, the form items [0] is defined using the newwin function, the other eight forms are defined as the subforms of the items [0] form. here, items [0] is used to draw a border around the menu, and other forms are used to display the selected cells in the menu. similarly, they will not overwrite the border on the menu. in order to distinguish between the selected and unselected states, it is necessary to make the selected unit background color different from other ones. this is the last and third sentence of this function. The background color of the first unit in the menu is different from that of others. This is because after the menu is popped up, the first unit is the selected state. WINDOW **draw_menu(int start_col){ int i; WINDOW **items; items=(WINDOW **)malloc(9*sizeof(WINDOW *)); items[0]=newwin(10,19,1,start_col); wbkgd(items[0],COLOR_PAIR(2)); box(items[0],ACS_VLINE,ACS_HLINE); items[1]=subwin(items[0],1,17,2,start_col+1); items[2]=subwin(items[0],1,17,3,start_col+1); items[3]=subwin(items[0],1,17,4,start_col+1); items[4]=subwin(items[0],1,17,5,start_col+1); items[5]=subwin(items[0],1,17,6,start_col+1); items[6]=subwin(items[0],1,17,7,start_col+1); items[7]=subwin(items[0],1,17,8,start_col+1); items[8]=subwin(items[0],1,17,9,start_col+1); for (i=1;i<9;i++) wprintw(items[i],"Item%d",i); wbkgd(items[1],COLOR_PAIR(1)); wrefresh(items[0]); return items;} The following function deletes the menu form defined by the above function. It first deletes the form using the delwin function, and then releases the memory unit of the items pointer. void delete_menu(WINDOW **items,int count){ int i; for (i=0;i<count;i++) delwin(items[i]); free(items);} The scroll_menu function allows us to move up and down the menu selection item. It reads the key value on the keyboard through getch. If we press the move up or move down arrow key on the keyboard, the previous or next item of the menu selection item is selected. recall what we just said. The background color of the selected item will be different from that of the unselected one. if it is a left or right direction key, the current menu will be closed, and another menu will be opened. if you press the Enter key, the selected unit value is returned. if you press the ESC key, the menu will be closed without any selection items. The following function ignores other input keys. getch can read key values from the keyboard, because keypad (stdscr, true) is used in the program and the return value is assigned to an int type variable instead of a char type variable, this is because int variables can indicate a value larger than char. int scroll_menu(WINDOW **items,int count,int menu_start_col){ int key; int; while (1) { key=getch(); if (key==KEY_DOWN || key==KEY_UP) { wbkgd(items[selected+1],COLOR_PAIR(2)); wnoutrefresh(items[selected+1]); if (key==KEY_DOWN) { selected=(selected+1) % count; } else { selected=(selected+count-1) % count; } wbkgd(items[selected+1],COLOR_PAIR(1)); wnoutrefresh(items[selected+1]); doupdate(); } else if (key==KEY_LEFT || key==KEY_RIGHT) { delete_menu(items,count+1); touchwin(stdscr); refresh(); items=draw_menu(20-menu_start_col); return scroll_menu(items,8,20-menu_start_col); } else if (key==ESCAPE) { return -1; } else if (key==ENTER) { return selected; } }} The last part is our main part. it uses all the functions described and written above to make the program work properly. it also reads the key value through getch to determine whether F1 or F2 is pressed, and uses draw_menu to draw the menu on the corresponding menu form. call the scroll_menu function to select a menu. When scroll_menu returns, it deletes the menu form and displays the selected unit content in the Information column. I must mention the function touchwin. if you do not call touchwin immediately after the menu is closed, the last menu will remain on the screen. this is because when calling refresh, the menu function does not completely change the content of stdscr. it did not re-write the data to stdscr, because it thought the form content had not changed. the touchwin function sets the flag spaces in all window structures, which notifies refresh to refresh all rows in the form, and the value is changed, so that the next time you refresh the entire form, write the form again even if the content of the form is not changed. after the menu is closed, the selected menu information stays on stdscr. the menu does not write data on stdscr because it opens a new subwindow. int main(){ int key; WINDOW *menubar,*messagebar; init_curses(); bkgd(COLOR_PAIR(1)); menubar=subwin(stdscr,1,80,0,0); messagebar=subwin(stdscr,1,79,23,1); draw_menubar(menubar); move(2,1); printw("Press F1 or F2 to open the menus. "); printw("ESC quits."); refresh(); do { int selected_item; WINDOW **menu_items; key=getch(); werase(messagebar); wrefresh(messagebar); if (key==KEY_F(1)) { menu_items=draw_menu(0); selected_item=scroll_menu(menu_items,8,0); delete_menu(menu_items,9); if (selected_item<0) wprintw(messagebar,"You haven't selected any item."); else wprintw(messagebar, "You have selected menu item %d.",selected_item+1); touchwin(stdscr); refresh(); } else if (key==KEY_F(2)) { menu_items=draw_menu(20); selected_item=scroll_menu(menu_items,8,20); delete_menu(menu_items,9); if (selected_item<0) wprintw(messagebar,"You haven't selected any item."); else wprintw(messagebar, "You have selected menu item %d.",selected_item+1); touchwin(stdscr); refresh(); } } while (key!=ESCAPE); delwin(menubar); delwin(messagebar); endwin(); return 0;} If you copy the code to a file, assuming the name is example. C and all my comments are removed, you can compile it using the following method: gcc -Wall example.c -o example -lcurses To test a program, you can download it in the reference section. SummaryI 've talked a lot about ncurses, which should be enough to create a nice interface for your program. there are also many convenient functions that are not mentioned here. You can find a lot of useful information in man pages of several functions that I often ask. after reading it, you will understand that what I mentioned here is just an introduction. Reference Program: example. c #include <curses.h>#include <stdlib.h>#define ENTER 10#define ESCAPE 27void init_curses(){ initscr(); start_color(); init_pair(1,COLOR_WHITE,COLOR_BLUE); init_pair(2,COLOR_BLUE,COLOR_WHITE); init_pair(3,COLOR_RED,COLOR_WHITE); curs_set(0); noecho(); keypad(stdscr,TRUE);}void draw_menubar(WINDOW *menubar){ wbkgd(menubar,COLOR_PAIR(2)); waddstr(menubar,"Menu1"); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F1)"); wattroff(menubar,COLOR_PAIR(3)); wmove(menubar,0,20); waddstr(menubar,"Menu2"); wattron(menubar,COLOR_PAIR(3)); waddstr(menubar,"(F2)"); wattroff(menubar,COLOR_PAIR(3));}WINDOW **draw_menu(int start_col){ int i; WINDOW **items; items=(WINDOW **)malloc(9*sizeof(WINDOW *)); items[0]=newwin(10,19,1,start_col); wbkgd(items[0],COLOR_PAIR(2)); box(items[0],ACS_VLINE,ACS_HLINE); items[1]=subwin(items[0],1,17,2,start_col+1); items[2]=subwin(items[0],1,17,3,start_col+1); items[3]=subwin(items[0],1,17,4,start_col+1); items[4]=subwin(items[0],1,17,5,start_col+1); items[5]=subwin(items[0],1,17,6,start_col+1); items[6]=subwin(items[0],1,17,7,start_col+1); items[7]=subwin(items[0],1,17,8,start_col+1); items[8]=subwin(items[0],1,17,9,start_col+1); for (i=1;i<9;i++) wprintw(items[i],"Item%d",i); wbkgd(items[1],COLOR_PAIR(1)); wrefresh(items[0]); return items;}void delete_menu(WINDOW **items,int count){ int i; for (i=0;i<count;i++) delwin(items[i]); free(items);}int scroll_menu(WINDOW **items,int count,int menu_start_col){ int key; int; while (1) { key=getch(); if (key==KEY_DOWN || key==KEY_UP) { wbkgd(items[selected+1],COLOR_PAIR(2)); wnoutrefresh(items[selected+1]); if (key==KEY_DOWN) { selected=(selected+1) % count; } else { selected=(selected+count-1) % count; } wbkgd(items[selected+1],COLOR_PAIR(1)); wnoutrefresh(items[selected+1]); doupdate(); } else if (key==KEY_LEFT || key==KEY_RIGHT) { delete_menu(items,count+1); touchwin(stdscr); refresh(); items=draw_menu(20-menu_start_col); return scroll_menu(items,8,20-menu_start_col); } else if (key==ESCAPE) { return -1; } else if (key==ENTER) { return selected; } }}int main(){ int key; WINDOW *menubar,*messagebar; init_curses(); bkgd(COLOR_PAIR(1)); menubar=subwin(stdscr,1,80,0,0); messagebar=subwin(stdscr,1,79,23,1); draw_menubar(menubar); move(2,1); printw("Press F1 or F2 to open the menus. "); printw("ESC quits."); refresh(); do { int selected_item; WINDOW **menu_items; key=getch(); werase(messagebar); wrefresh(messagebar); if (key==KEY_F(1)) { menu_items=draw_menu(0); selected_item=scroll_menu(menu_items,8,0); delete_menu(menu_items,9); if (selected_item<0) wprintw(messagebar,"You haven't selected any item."); else wprintw(messagebar, "You have selected menu item %d.",selected_item+1); touchwin(stdscr); refresh(); } else if (key==KEY_F(2)) { menu_items=draw_menu(20); selected_item=scroll_menu(menu_items,8,20); delete_menu(menu_items,9); if (selected_item<0) wprintw(messagebar,"You haven't selected any item."); else wprintw(messagebar, "You have selected menu item %d.",selected_item+1); touchwin(stdscr); refresh(); } } while (key!=ESCAPE); delwin(menubar); delwin(messagebar); endwin(); return 0;} |