第六章 使用curses函数库管理基于文本的屏幕
来源:互联网 发布:淘宝如何做企业店铺 编辑:程序博客网 时间:2024/05/24 06:08
screen1.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>int main(){ initscr(); move(5, 15); printw("%s", "hello world"); refresh(); sleep(2); endwin(); exit(EXIT_SUCCESS);}
initscr, endwin:所有的curses程序必须以initscr函数开始,以endwin函数结束
#include <curses.h>WINDOW *initscr(void);int endwin(void);
- initscr函数在一个程序中只调用一次,如果成功,它返回一个指向stdscr结构的指针.如果失败,它就输出一条诊断错误信息并使程序退出
- endwin函数在成功时候返回OK,失败时返回ERR.
- 可以先调用endwin函数退出curses,然后通过调用clearok(stdscr, 1)和refresh函数继续curses操作.这实际上是首先让curses忘记物理屏幕的样子,然后强迫它执行一次完整的屏幕原文重现
输出到屏幕
#include <curses.h>int addch(const chtype char_to_add);int addchstr(chtype *const string string_to_add);int printw(char *format, ...);int refresh(void);int box(WINDOW *win_ptr, chtype vertical_char, chtype horizontal_char);int insch(chtype char_to_insert);int insertln(void);int delch(void);int deleteln(void);int beep(void);int flash(void);
- chtype实际上是unsigned long类型的一个typedef类型定义
- add系列函数在光标当前的位置添加指定的字符或者字符串
- printw函数采用与printf函数相同的方法对字符串进行格式化,然后将其添加到光标的当前位置
- refresh函数的作用是刷新物理屏幕,成功时候返回OK,发生错误时返回ERR
- box函数用来围绕一个窗口绘制方框
- insch函数插入一个字符,将已有字符向右移
- insertln函数的作用是插入一个空白行,将现有行一次向下移一行
- 两个delete函数的作用与上述两个insert函数正好相反
- 如果让程序发出声音,可以调用beep函数
- flash函数的作用是使屏幕发生闪烁,如果无法产生闪烁效果,他将尝试在终端发出声音
从屏幕读取
#include <curses.h>chtype inch(void);int instr(char *string);int innstr(char *string, int number_of_characters);
- inch函数总是可用的,但是instr和innstr函数并不总被支持
- inch函数返回光标当前位置的字符及其属性信息
- 注意inch返回的并不是一个字符,而是一个chtype类型的变量
- instr和innstr函数则将返回内容写到字符数组中
清除屏幕
#include <curses.h>int erase(void);int clear(void);int clrtobot(void);int clrtoeol(void);
- erase函数在每个屏幕位置写上空白字符.clear函数的功能类似erase函数他也用于清屏
- clear函数可以通过在内部调用一个底层函数clearok来强制重现屏幕原文.
- clearok函数会强制执行清屏操作,并在下一次调用refresh函数时重现屏幕原文
- clrtobot函数清除当前光标位置直到屏幕结尾的所有内容
- clrtoeol函数清除当前光标位置直到光标所处行行尾的所有内容
移动光标
#include <curses.h>int move(int new_y, int new_x);int leaveok(WINDOW *window_ptr, bool leave_flag);
- move函数用来将裸机光标的位置移到指定地点.
- leaveok函数设置了一个标志,该标志用于控制在屏幕刷新后cueses将物理光标放置的位置,默认情况下,该标志设置为flase,这意味着屏幕刷新后,硬件光标将停留在屏幕上逻辑光标所处的位置.如果该标志被设置为true,则硬件光标会被随机的放在屏幕上任意的位置
字符属性
#include <curses.h>int attron(chtype attribute);int attroff(chtype attribute);int attrset(chtyppe attribute);int standout(void);int standend(void);
- 每个cueses字符都可以有一些属性用于控制字符在屏幕上的显示方式,前提是用于显示的硬件设备能够支持要求的属性.
- 预定义的属性有:A_BLINK, A_BOLD, A_DIM, A_REVERSE, A_STANDOUT和A_UNDERLINE
- attrset函数设置cueses的属性
- attron和attroff函数在不影响其它属性的前提下启用或者关闭指定的属性
- standout和standend函数提供了一种更加通用的强调或者”突出”模式,在大多数终端上它通常被映射为反白显示
moveadd.c:移动,插入和属性
#include <stdio.h>#include <unistd.h>#include <stdlib.h>#include <string.h>#include <curses.h>int main(){ const char witch_one[] = " First Witch "; const char witch_two[] = " Second Witch "; const char *scan_ptr; initscr(); move(5, 15); attron(A_BOLD); printw("%s", "Macbeth"); attroff(A_BOLD); refresh(); sleep(1); move(8, 15); attron(A_STANDOUT); printw("%s", "Thunder and lightning"); attroff(A_STANDOUT); refresh(); sleep(1); move(10, 10); printw("%s", "When shall we stree meet again"); move(11, 23); printw("%s", "In thunder, lightning, or in rain?"); move(13, 10); printw("%s", "when the hurglyburly's done,"); move(14, 23); printw("%s", "when the battle's lost and won."); refresh(); sleep(1); attron(A_DIM); scan_ptr = witch_one + strlen(witch_one) - 1; while(scan_ptr != witch_one){ move(10, 10); insch(*scan_ptr--); } scan_ptr = witch_two + strlen(witch_two) - 1; while(scan_ptr != witch_two){ move(13, 10); insch(*scan_ptr--); } attroff(A_DIM); refresh(); sleep(1); move(LINES -1, COLS -1); refresh(); sleep(1); endwin(); exit(EXIT_SUCCESS);}
- scan_ptr = witch_one + strlen(witch_one) - 1: 表示sca_ptr的地址相当一witch_one的地址向右移动strlen(witch) - 1
键盘模式
#include <curses.h>int echo(void);int noecho(void);int cbreak(void);int nocbreak(void);int raw(void);int noraw(void);
- 两个echo函数用于开启或关闭输入字符的回显功能
- 预处理模式(cooked模式)是基于行的,只有在用户按下回车键之后才会被传送给程序
- cbreak模式:在这种模式下字符一经键入就被立即传递给程序
- raw函数调用的作用是关闭特殊字符的处理
- nocbreak函数调用将输入模式重新设置为cooked模式,但特殊字符的处理方式保持不变
- noraw函数调用同时恢复cooked模式和特殊字符处理功能
键盘输入
#include <curses.h>int getch(void);int getstr(char *string);int getnstr(char *string, int number_of_characters);int scanw(char *format, ...);
- 这些函数的行为与非curses版本的getchar,gets和scanf非常类似
- getstr函数对齐返回的字符串的长度没有限制,所以使用这个函数时要非常小心,如果所使用的curses版本支持getnstr函数(他可以限制对读取的字符数目加以限制),你就应该尽可能的使用它来代替getstr函数
ipmode.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>#include <string.h>#define PW_LEN 256#define NAME_LEN 256int main(){ char name[NAME_LEN]; char password[PW_LEN]; const char *real_password = "xyzzy"; int i = 0; initscr(); move(5, 10); printw("%s", "Please login: "); move(7, 10); printw("%s", "User name:"); getstr(name); move(8, 10); printw("%s", "Password: "); refresh(); cbreak(); noecho(); memset(password, '\0', sizeof(password)); while(i < PW_LEN){ password[i] = getch(); if(password[i] == '\n') break; move(8, 20 + i); addch('*'); refresh(); i++; } echo(); nocbreak(); move(11, 10); if(strncmp(real_password, password, strlen(real_password)) == 0) printw("%s", "Correct"); else printw("%s", "Incorrect"); printw("%s", " password"); refresh(); sleep(2); endwin(); exit(EXIT_SUCCESS);}
- void *memset(void *s, int ch, size_t n);
- 函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。
- memset:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法
WINDOW结构
#include <curses.h>WINDOW *newwin(int num_of_lines, int num_of_cols, int start_y, int start_x);int delwin(WINDOW *window_to_delete);
- newwin函数的作用是创建一个新窗口.他返回一个指向新窗口的指针,如果新窗口创建失败则返回null
- 如果想让新窗口的右下角正好落在屏幕的右下角,,可以将newwin函数的行,列参数设为0
- 所有窗口的范围都必须在当前屏幕范围之内,如果新窗口任何一部分落在当前屏幕范围之外,则newwin函数调用将失败
- delwin函数的作用是删除一个先前通过newwin函数创建的窗口.因为调用newwin函数可能会给新窗口分配内存,所以当不再需要这些窗口时,不要忘记通过delwin函数将其删除
- 千万不要尝试删除curses自己的窗口stdscr和curscr
通用函数
#include <curses.h>int addch(const chtype char);int waddch(WINDOW *window_pointer, const chtype char);int mvaddch(int y, int x, const chtype char);int mvwaddch(WINDOW *window_pointer, int y, int x, const chtype char);int printw(char *format, ...);int wprintw(WINDOW *window_pointer, char *format, ...);int mvprintw(int y, int x, char *format, ...);int mvwprintw(WINDOW *window_pointer, int y, int x, char *format, ...);
- 前缀w用于窗口,mv用于光标移动,mvw用于在窗口内移动光标
- 如果给函数增加了w前缀,就必须在该函数的参数表的最前面加一个WINDOW指针参数
- 如果给函数增加的是mv前缀,则需要在函数的参数表的最前面增加两个参数分别是纵坐标y和横坐标x,两个坐标指定了执行操作的位置
- 如果给函数增加mvw前缀,就需要多传递3个参数,它们分别是一个WINDOW指针,y和x坐标值
移动和更新窗口
#include <curses.h>int mvwin(WINDOW *window_to_move, int new_y, int new_x);int wrefresh(WINDOW *window_ptr);int wclear(WINDOW *window_ptr);int werase(WINDOW *window_ptr);int touchwin(WINDOW *window_ptr);int scrollok(WINDOW *window_ptr, bool scroll_flag);int scroll(WINDOW *window_ptr);
- mvwin函数的作用是在屏幕上移动一个窗口,不允许窗口的任何部分查处屏幕范围
- wrefresh, wclear和werases函数分别是前面介绍的refresh, clear, erase函数的通用版本.他们只是多了一个WINDOW指针参数,从而可针对特定的窗口进行操作,而不仅仅局限于stdscr
- touchwin函数非常特殊,她的作用是通知curses函数库其指针参数指向的窗口的内容已发生改变
- 两个scroll函数控制窗口的卷屏.如果传递给scrollok函数的布尔值值true(通常是非零值),则允许卷屏.默认情况下是不允许卷屏的.scroll函数的作用只是把窗口的内容上卷一行
mutiw1.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>int main(){ WINDOW *new_window_ptr; WINDOW *popup_window_ptr; int x_loop; int y_loop; char a_letter = 'a'; initscr(); move(5, 5); printw("%s", "Testing mutiple windows"); refresh(); for(y_loop = 0; y_loop < LINES - 1; y_loop++){ for(x_loop = 0; x_loop < COLS - 1; x_loop++){ mvwaddch(stdscr, y_loop, x_loop, a_letter); a_letter++; if(a_letter > 'z') a_letter = 'a'; } } /* Update the screen */ refresh(); sleep(2); new_window_ptr = newwin(10, 25, 5, 5); mvwprintw(new_window_ptr, 2, 2, "%s", "Hello World"); mvwprintw(new_window_ptr, 5, 2, "%s", "Notice how very long lines wrap inside the window"); wrefresh(new_window_ptr); sleep(2); a_letter = '0'; for(y_loop = 0; y_loop < LINES - 1; y_loop++){ for(x_loop = 0; x_loop < COLS - 1; x_loop++){ mvwaddch(stdscr, y_loop, x_loop, a_letter); a_letter++; if(a_letter > '9') a_letter = '0'; } } refresh(); sleep(2); wrefresh(new_window_ptr); sleep(2); touchwin(new_window_ptr); wrefresh(new_window_ptr); sleep(2); popup_window_ptr = newwin(10, 20, 8, 8); box(popup_window_ptr, '|', '-'); mvwprintw(popup_window_ptr, 5, 2, "%s", "Pop Up window!"); wrefresh(popup_window_ptr); sleep(2); touchwin(new_window_ptr); wrefresh(new_window_ptr); sleep(2); wclear(new_window_ptr); wrefresh(new_window_ptr); sleep(2); delwin(new_window_ptr); touchwin(popup_window_ptr); wrefresh(popup_window_ptr); sleep(2); delwin(popup_window_ptr); touchwin(stdscr); refresh(); sleep(2); endwin(); exit(EXIT_SUCCESS);}
优化屏幕刷新
#include <curses.h>int wnoutrefresh(WINDOW *window_ptr);int doupdate(void);
- wnoutrefresh函数用于决定把哪些字符发送到屏幕上,但是他并不真正的发送这些字符,真正将更新发送到终端的工作由doupdate函数来完成.
- 如果只是调用了wnoutrefresh函数之后立即调用doupdate函数,则效果和直接调用wrefresh一样
- 如果想重新绘制多个窗口,你可以为每个窗口分别调用wnoutrefresh函数,然后只需要在最后一个wnoutrefresh之后调用一次doupdate函数
子窗口
#include <curses.h>WINDOW *subwin(WINDOW *parent, int num_of_lines,int num_of_cols, int start_y, int start_x);int delwin(WINDOW *window_to_delete);
- subwin函数的参数几乎与newwin函数一样,子窗口的删除过程也和其他窗口一样
- 区别:子窗口没有自己独立的屏幕字符存储空间,他们与父窗口共享同一字符存储空间,这意味着对子窗口内容的任何修改都会反应到父窗口中
subsc1.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>int main(){ WINDOW *sub_window_ptr; int x_loop; int y_loop; int counter; char a_letter = '1'; initscr(); for(y_loop = 0; y_loop < LINES - 1; y_loop++){ for(x_loop = 0; x_loop < COLS - 1; x_loop++){ mvwaddch(stdscr, y_loop, x_loop, a_letter); a_letter++; if(a_letter > '9') a_letter = '1'; } } sub_window_ptr = subwin(stdscr, 10, 20, 10, 10); scrollok(sub_window_ptr, 1); touchwin(stdscr); refresh(); sleep(3); werase(sub_window_ptr); mvwprintw(sub_window_ptr, 2, 0, "%s", "This window will now scroll"); wrefresh(sub_window_ptr); sleep(1); for(counter = 1; counter < 10; counter++){ wprintw(sub_window_ptr, "%s", "This text is both wraping and scrolling"); wrefresh(sub_window_ptr); sleep(1); } delwin(sub_window_ptr); touchwin(stdscr); refresh(); sleep(2); endwin(); exit(EXIT_FAILURE);}
keypad模式
#include <curses.h>int keypad(WINDOW *window_ptr, bool keypad_flag);
- keypad模式主要用于处理键盘的功能.例如方向键和功能键等
- 头文件curses.h通过一组以KEY_为前缀的定义来管理逻辑键
- 函数调用成功时返回OK.失败时,返回ERR
- 在该模式中curses将接管按键转义序列的处理工作,读取键盘操作不仅能够返回用户按下的键,还将返回与逻辑按键对应的KEY_定义
keypad模式的三个小小限制
- 识别escape转义序列的过程是与时间相关的
- 为了让curses能够区分”单独按下Escape键”和”一个以Escape字符开头的键盘转义序列”,它必须等待一小段时间
- curses不能吹二义性的转义序列
keypad.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>#define LOCAL_ESCAPE_KEY 27int main(){ int key; initscr(); crmode(); keypad(stdscr, true); noecho(); clear(); mvprintw(5, 5, "%s", "keypad demonstration.Press 'q' to quit"); move(7, 5); refresh(); key = getch(); while(key != ERR && key != 'q'){ move(7, 5); clrtoeol(); if((key >= 'A' && key <= 'Z') || (key >= 'a' && key <= 'z')){ printw("key was %c", (char)key); } else { switch(key){ case LOCAL_ESCAPE_KEY: printw("%s", "escape key"); break; case KEY_END: printw("%s", "END key"); break; case KEY_BEG: printw("%s", "BEGINNING key"); break; case KEY_RIGHT: printw("%s", "RIGHT key"); break; case KEY_LEFT: printw("%s", "LEFT key"); break; case KEY_UP: printw("%s", "UP key"); break; case KEY_DOWN: printw("%s", "DOWN key"); break; default: printw("%s", "Unmatched-%d", key); break; } } refresh(); key = getch(); } endwin(); exit(EXIT_SUCCESS);}
彩色显示
#include <curses.h>bool has_colors(void);int start_color(void);int init_pair(short pair_number, short foreground, short background);int COLOR_PAIR(int pair_number);int pair_content(short pair_number,short *foreground, short *background);
- 如果终端支持彩色功能,has_colors函数将返回true.然后你需要调用start_color函数,如果该函数成功初始化了颜色显示功能,他将返回OK.
- 一旦start_color函数调用成功,变量COLOR_PAIRS将被设置成最大值64,变量COLORS定义将被设置为最大值8
- 在把颜色作为属性使用之前,你必须先调用init_pair函数对准备使用的颜色组合进行初始化
- 对颜色属性的访问是通过COLOR_PAIR函数来完成
- pair_content作用是获取已定义的颜色组合的信息
color.c
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <curses.h>int main(){ int i; initscr(); if(!has_colors()){ endwin(); fprintf(stderr, "Error, no color surport on this terminal\n"); exit(1); } if(start_color() != OK){ endwin(); fprintf(stderr, "Error, could not initialize colors\n"); exit(2); } clear(); mvprintw(5, 5, "There are %d COLORS, and %d COLOR_PAIRS avaiable", COLORS, COLOR_PAIRS); refresh(); init_pair(1, COLOR_RED, COLOR_BLACK); init_pair(2, COLOR_RED, COLOR_GREEN); init_pair(3, COLOR_GREEN, COLOR_RED); init_pair(4, COLOR_YELLOW, COLOR_BLUE); init_pair(5, COLOR_BLACK, COLOR_WHITE); init_pair(6, COLOR_MAGENTA, COLOR_BLUE); init_pair(7, COLOR_CYAN, COLOR_WHITE); for(i = 1; i <= 7; i++){ attroff(A_BOLD); attrset(COLOR_PAIR(i)); mvprintw(5 + i, 5, "Color pair %d", i); attrset(COLOR_PAIR(i) | A_BOLD); mvprintw(5 + i, 25, "Bold color pair %d", i); refresh(); sleep(2); } endwin(); exit(EXIT_SUCCESS);}
pad
#include <curses.h>WINDOW *newpad(int num_of_lines,int num_of_columns);int prefresh(WINDOW *pad_ptr, int pad_row, int pad_column, int screen_row_min, int screen_col_min, int screen_row_max, int screen_col_max);
- newpad函数的返回值是一个指向WINDOW结构的指针,这和newwin一样,pad用delwin函数来删除
- pad使用不同的函数prefresh来执行刷新操作,这个函数的的作用是将pad从坐标(pad_row, pad_column)开始区域写到屏幕上指定的显示区域,该区域的范围从坐标(int screen_row_min, int screen_row_max, int screen_col_max)
- curses还提供了,pnoutrefresh,它的作用和函数wnoutrefresh一样
pad.c
#include <unistd.h>#include <stdlib.h>#include <curses.h>int main(){ WINDOW *pad_ptr; int x, y; int pad_lines; int pad_cols; char disp_char; initscr(); pad_lines = LINES + 50; pad_cols = COLS + 50; pad_ptr = newpad(pad_lines, pad_cols); disp_char = 'a'; for(x = 0; x < pad_lines; x++){ for(y = 0; y < pad_cols; y++){ mvwaddch(pad_ptr, x, y, disp_char); if(disp_char == 'z') disp_char = 'a'; disp_char++; } } prefresh(pad_ptr, 0, 0, 2, 2, 9, 9); sleep(10); prefresh(pad_ptr, LINES + 5, COLS + 7, 5, 5, 21, 19); sleep(10); delwin(pad_ptr); endwin(); exit(EXIT_SUCCESS);}
main.c
#include <unistd.h>#include <stdlib.h>#include <stdio.h>#include <string.h>#include <curses.h>#define MAX_STRING 80 /* Longest allowed response */#define MAX_ENTRY 1024 /* Longest allowed database entry */#define MESSAGE_LINE 6 /* Misc. messages on this line */#define ERROR_LINE 22 /* Line to use for errors */#define Q_LINE 20 /* Line for question */#define PROMPT_LINE 18 /* Line for prompting on */static char current_cd[MAX_STRING] = "\0";static char current_cat[MAX_STRING];const char *title_file = "title.cdb";const char *tracks_file = "tracks.cdb";const char *temp_file = "cdb.tmp";void clear_all_screen(void);void get_return(void);int get_confirm(void);int ger_choice(char *greet, char *choices[]);void draw_menu(char *options[], int highlight, int start_row, int strat_col);void insert_title(char *cdtitle);void get_string(char *string);void add_record(void);void count_cds(void);void find_cd(void);void list_tracks(void);void remove_tracks(void);void remove_cd(void);void update_cd(void);char *main_menu[] = { "add new CD", "find CD", "count CDs and tracks in the catalog", "quit", 0};char *extended_menu[] = { "add new CD", "find CD", "count CDs and tracks in the catalog", "list tracks on current CD", "remove current CD", "update track information", "quit", 0};int main(){ int choice; initscr(); do { choice = get_choice("Options:", current_cd[0] ? extended_menu : main_menu); switch(choice){ case 'q': break; case 'a': add_record(); break; case 'c': count_cds(); break; case 'f': find_cd(); break; case 'l': list_tracks(); break; case 'r': remove_cd(); case 'u': update_cd(); break; } } while(choice != 'q');}int get_choice(char *greet, char *choices[]){ static int selected_row = 0; int max_row = 0; int start_screenrow = MESSAGE_LINE, start_screencol = 10; char **option; int selected; int key = 0; option = choices; while(*option){ max_row++; option++; } /* protect against menu getting shorter when CD seleted */ if(selected_row > max_row){ selected_row = 0; } clear_all_screen(); mvprintw(start_screenrow - 2, start_screencol, greet); keypad(stdscr, true); cbreak(); noecho(); key = 0; while(key != 'q' && key != KEY_ENTER && key != '\n'){ if(key == KEY_UP){ if(selected_row == 0) selected_row = max_row - 1; else selected_row--; } if(key == KEY_DOWN){ if(selected_row == (max_row - 1)) selected_row = 0; else selected_row++; } selected = *choices[selected_row]; draw_menu(choices, selected_row, start_screenrow, start_screencol); key = getch(); } keypad(stdscr, false); nocbreak(); echo(); if(key == 'q') selected = 'q'; return selected;}void draw_menu(char *options[], int current_highlight, int start_row, int start_col){ int current_row = 0; char **option_ptr; char *txt_ptr; option_ptr = options; while(*option_ptr){ if(current_row == current_highlight) attron(A_STANDOUT); txt_ptr = options[current_row]; txt_ptr++; mvprintw(start_row + current_row, start_col, "%s", txt_ptr); if(current_row == current_highlight) attroff(A_STANDOUT); current_row++; option_ptr++; } mvprintw(start_row + current_row + 3, start_col, "Move highlight then press Return"); refresh();}void clear_all_screen(){ clear(); mvprintw(2, 20, "%s", "CD Database Application"); if(current_cd[0]){ mvprintw(ERROR_LINE, 0, "Current CD: %s: %s\n", current_cat, current_cd); } refresh();}void add_record(){ char catalog_number[MAX_STRING]; char cd_title[MAX_STRING]; char cd_type[MAX_STRING]; char cd_artist[MAX_STRING]; char cd_entry[MAX_STRING]; int screenrow = MESSAGE_LINE; int screencol = 10; clear_all_screen(); mvprintw(screenrow, screencol, "Enter new CD details"); screenrow += 2; mvprintw(screenrow, screencol, "Catalog Number: "); get_string(catalog_number); screenrow++; mvprintw(screenrow, screencol, " CD title: "); get_string(cd_title); screenrow++; mvprintw(screenrow, screencol, " CD type: "); get_string(cd_type); screenrow++; mvprintw(screenrow, screencol, " Artist: "); get_string(cd_artist); screenrow++; mvprintw(PROMPT_LINE - 2, 5, "About to add this new entry:"); sprintf(cd_entry, "%s,%s,%s,%s", catalog_number, cd_title, cd_type, cd_artist); mvprintw(PROMPT_LINE, 5, "%s", cd_entry); refresh(); if(get_confirm()){ insert_title(cd_entry); strcpy(current_cd, cd_title); strcpy(current_cat, catalog_number); }}void get_string(char *string){ int len; wgetnstr(stdscr, string, MAX_STRING); len = strlen(string); if(len > 0 && string[len -1] == '\n') string[len -1] = '\0';}int get_confirm(){ int confirmed = 0; char first_char; mvprintw(Q_LINE, 5, "Are you sure? "); clrtoeol(); refresh(); cbreak(); first_char = getch(); if(first_char == 'Y' || first_char == 'y'){ confirmed = 1; } nocbreak(); if(!confirmed){ mvprintw(Q_LINE, 1, " Canncelled"); clrtoeol(); refresh(); sleep(2); } return confirmed;}void insert_title(char *cdtitle){ FILE *fp = fopen(title_file, "a"); if(!fp){ mvprintw(ERROR_LINE, 0, "can not open CD titles database"); } else { fprintf(fp, "%s\n", cdtitle); fclose(fp); }}#define BOXED_LINES 11#define BOXED_ROWS 60#define BOX_LINE_POS 8#define BOX_ROW_POS 2void update_cd(){ FILE *tracks_fp; char track_name[MAX_STRING]; int len; int track = 1; int screen_line = 1; WINDOW *box_window_ptr; WINDOW *sub_window_ptr; clear_all_screen(); mvprintw(PROMPT_LINE, 0, "Re-entering tracks for CD. "); if(!get_confirm()) return; move(PROMPT_LINE, 0); clrtoeol(); remove_tracks(); mvprintw(MESSAGE_LINE, 0, "Enter a blank line to finish"); tracks_fp = fopen(tracks_file, "a"); box_window_ptr = subwin(stdscr, BOXED_LINES + 2, BOXED_ROWS + 2, BOX_LINE_POS - 1, BOX_ROW_POS -1); if(!box_window_ptr) return; box(box_window_ptr, ACS_VLINE, ACS_HLINE); sub_window_ptr = subwin(stdscr, BOXED_LINES, BOXED_ROWS, BOX_LINE_POS, BOX_ROW_POS); if(!sub_window_ptr) return; scrollok(sub_window_ptr, true); werase(sub_window_ptr); touchwin(stdscr); do{ mvwprintw(sub_window_ptr, screen_line++, BOX_ROW_POS + 2, "Track %d:", track); clrtoeol(); refresh(); wgetnstr(sub_window_ptr, track_name, MAX_STRING); len = strlen(track_name); if(len > 0 && track_name[len - 1] == '\n') track_name[len -1] = '\0'; if(*track_name) fprintf(tracks_fp, "%s,%d,%s\n", current_cat, track, track_name); track++; if(screen_line > BOXED_LINES - 1){ scroll(sub_window_ptr); screen_line--; } } while(*track_name); delwin(sub_window_ptr); fclose(tracks_fp);}void remove_cd(){ FILE *titles_fp, *temp_fp; char entry[MAX_STRING]; int cat_length; if(current_cd[0] == '\0') return; clear_all_screen(); mvprintw(PROMPT_LINE, 0, "About to remove CD %s: %s. ", current_cat, current_cd); if(!get_confirm()) return; cat_length = strlen(current_cat); /* copy the titles file to a temporary, ignoring this CD */ titles_fp = fopen(title_file, "r"); temp_fp= fopen(temp_file, "w"); while(fgets(entry, MAX_STRING, titles_fp)){ /*compare catalog number and copy entry if no match */ if(strncmp(current_cat, entry, cat_length) != 0) fputs(entry, temp_fp); } fclose(titles_fp); fclose(temp_fp); /* delete the titles file, and rename the temporary file */ unlink(title_file); rename(temp_file, title_file); /* Now do the same for the tracks file */ remove_tracks(); /* Reset the CD to "None" */ current_cd[0] = '\0';}void remove_tracks(){ FILE *tracks_fp, *temp_fp; char entry[MAX_STRING]; int cat_length; if(current_cd[0] == '0') return; cat_length = strlen(current_cat); tracks_fp = fopen(tracks_file, "r"); if(tracks_fp == (FILE *)NULL) return; temp_fp = fopen(temp_file, "w"); while(fgets(entry, MAX_STRING, tracks_fp)){ /* compare catalog number and copy entry if no match */ if(strncmp(current_cat, entry, cat_length) != 0) fputs(entry, temp_fp); } fclose(tracks_fp); fclose(temp_fp); /* delete the tracks file, and rename the temporary file */ unlink(tracks_file); rename(temp_file, tracks_file);}void count_cds(){ FILE *titles_fp, *tracks_fp; char entry[MAX_STRING]; int titles = 0; int tracks = 0; titles_fp = fopen(title_file, "r"); if(titles_fp){ while(fgets(entry, MAX_STRING, titles_fp)) titles++; fclose(titles_fp); } tracks_fp = fopen(tracks_file, "r"); if(tracks_fp){ while(fgets(entry, MAX_STRING, tracks_fp)) tracks++; fclose(tracks_fp); } mvprintw(ERROR_LINE, 0, "Database contains %d titles, with a total of %d tracks.", titles, tracks); get_return();}void find_cd(){ char match[MAX_STRING], entry[MAX_STRING]; FILE *titles_fp; int count = 0; char *found, *title, *catalog; mvprintw(Q_LINE, 0, "Enter a string to search for in CD titles: "); get_string(match); titles_fp = fopen(title_file, "r"); if(titles_fp){ while(fgets(entry, MAX_STRING, titles_fp)){ /* Skip past catalog number */ catalog = entry; if(found == strstr(catalog, ",")){ *found == '\0'; title = found + 1; /* Zap the next comma in the entry to reduce it to title only */ if(found == strstr(title, ",")){ *found = '\0'; /* Now see if the match substring is present */ if(found == strstr(title, match)){ count++; strcpy(current_cd, title); strcpy(current_cat, catalog); } } } } fclose(titles_fp); } if(count != 1){ if(count == 0){ mvprintw(ERROR_LINE, 0, "Sorry, no matching CD found. "); } if(count > 1){ mvprintw(ERROR_LINE, 0, "Sorry, match is ambiguous: %d CDs found. ", count); } current_cd[0] = '\0'; get_return(); }}void list_tracks(){ FILE *tracks_fp; char entry[MAX_STRING]; int cat_length; int lines_op = 0; WINDOW *track_pad_ptr; int tracks = 0; int key; int first_line = 0; if(current_cd[0] == '\0'){ mvprintw(ERROR_LINE, 0, "You must select a CD first. "); get_return(); return; } clear_all_screen(); cat_length = strlen(current_cat); /* First count the number of tracks for the current CD */ tracks_fp = fopen(tracks_file, "r"); if(!tracks_fp) return; while(fgets(entry, MAX_STRING, tracks_fp)){ if(strncmp(current_cat, entry, cat_length) == 0); tracks++; } fclose(tracks_fp); /* Make a new pad, ensure that even if there is only a single track the PAD is large enough so the later prefresh() is always valid. */ track_pad_ptr = newpad(tracks + 1 + BOXED_LINES, BOXED_ROWS + 1); if(!track_pad_ptr) return; tracks_fp = fopen(tracks_file, "r"); if(!tracks_fp) return; mvprintw(4, 0, "CD track listing\n"); /* write the track information into the pad */ while(fgets(entry, MAX_STRING, tracks_fp)){ /* Compare catalog number and output rest of entry */ if(strncmp(current_cat, entry, cat_length) == 0){ mvwprintw(track_pad_ptr, lines_op++, 0, "%s", entry + cat_length + 1); } } fclose(tracks_fp); if(lines_op > BOXED_LINES){ mvprintw(MESSAGE_LINE, 0, "Cursor keys to scroll, RETURN or q to exit"); } else{ mvprintw(MESSAGE_LINE, 0, "RETURN or q to exit"); } wrefresh(stdscr); keypad(stdscr, true); cbreak(); noecho(); key = 0; while(key != 'q' && key != KEY_ENTER && key != '\n'){ if(key == KEY_UP){ if(first_line > 0) first_line--; } if(key == KEY_DOWN){ if(first_line + BOXED_LINES + 1 < tracks) first_line++; } /* now draw the approptiate part of the pad on the screen */ prefresh(track_pad_ptr, first_line, 0, BOX_LINE_POS, BOX_ROW_POS, BOX_LINE_POS + BOXED_LINES, BOX_ROW_POS + BOXED_ROWS); key = getch(); } delwin(track_pad_ptr); keypad(stdscr, false); nocbreak(); echo();}void get_return(){ int ch; mvprintw(23, 0, "%s", " Pass return "); refresh(); while((ch = getchar()) != '\n' && ch != EOF);}
0 0
- 第六章 使用curses函数库管理基于文本的屏幕
- 使用curses函数库管理基于文本的屏幕
- 9.使用 curses 函数库来管理基于文本的屏幕
- 使用curses管理基于文本的屏幕
- 使用curses管理基于文本的屏幕
- LINUX程序设计 使用curses函数库管理基于文本的屏幕 学习笔记
- 《Linux程序设计》——使用curses函数库管理基于文本的屏幕
- 使用curses函数管理基于文本的屏幕
- 第六章 curses函数库
- 使用curses函数库编辑屏幕
- Beginning Linux Programming 笔记(六)使用curses管理基于文本的终端
- curses函数库使用常见问题
- 第六章 认识Java的API---使用Java函数库
- Linux 中的 curses 函数库--- 使用 getch 必需
- 使用curses.h函数库实现字符动画
- Linux下curses函数库的学习
- linux中 curses.h函数库的应用
- 使用curses.h函数库实现字符动画 No.2
- 自定义渐变式炫酷动画的ListView下拉刷新
- 快速排序
- 第三章 文件操作
- 第四章 Linux环境
- 第五章 终端
- 第六章 使用curses函数库管理基于文本的屏幕
- HDU 1000:A + B Problem
- 第七章 数据管理
- Linux中GIT仓库的使用
- 第九章 开发工具
- [oracle] 常用函数 - rank
- CSS之背景属性
- 第十二章 POSIX线程
- CSS3与之前版本的区别