curses 메뉴화면 만들어봤습니다.
글쓴이: angra / 작성시간: 화, 2008/11/11 - 11:34오전
회사에서 쓸일이 생겨서 첨으로 curses 메뉴 화면 만들어봤습니다
인터넷에 있는 소스를 가져다가 입맛에 맞게 수정했는데, 좀 더
좋은 방법들이 많을듯하나 지금은 잘 모르겠네요. curses에서
제공하는 menu 라이브러리가 있지만 생각보다 쓰기 편한건 아니더군요
그래서 그냥 메뉴화면을 만들었습니다.
^^
-------------------------------------------
#include <curses.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <signal.h> #define ESCAPE 27 #define ENTER 10 char *seq_item[] = {"", "SUB_메뉴1", "SUB_메뉴2", "SUB_메뉴3", "SUB_메뉴4", "SUB_메뉴5"}; char *tr_item[] = {"", "SUB_메뉴1", "SUB_메뉴2", "SUB_메뉴3", "SUB_메뉴4"}; char *proc_item[] = {"", "SUB_메뉴1", "SUB_메뉴2", "SUB_메뉴3", "SUB_메뉴4"}; char *mng_item[] = {"", "SUB_메뉴1", "SUB_메뉴2", "SUB_메뉴3", "quit"}; /* title, status will be globall refresh */ WINDOW *titlebar, *statusbar; WINDOW *menubar; WINDOW *dataview; extern void refresh_status(char*); extern void Init_Mana(int, char**); extern void view_tr(WINDOW *, int , int); extern void view_proc(WINDOW *, int); extern void view_seq(WINDOW *, int); void init_screen() { initscr(); start_color(); noecho(); keypad(stdscr, TRUE); } void end_screen() { delwin(titlebar); delwin(statusbar); delwin(dataview); delwin(menubar); endwin(); exit(0); } static void end_proc(int p_signo) { char _Log_Buf [BUFSIZ]; strcat(_Log_Buf, " 프로세스를 종료합니다."); refresh_status(_Log_Buf); end_screen(); } static void Setsigfatal(void) { signal (SIGINT, end_proc); signal (SIGKILL, end_proc); signal (SIGQUIT, end_proc); signal (SIGILL, end_proc); signal (SIGTERM, end_proc); signal (SIGBUS, end_proc); signal (SIGSEGV, end_proc); signal (SIGHUP, end_proc); return; } void refresh_title() { time_t tloc; struct tm *tp; char date_time[60]; time (&tloc); tp = localtime(&tloc); strftime(date_time, 22, "%Y/%m/%d %H:%M:%S", tp); wmove(titlebar, 0, 2); waddstr(titlebar, "메뉴 테스트 시스템"); wmove(titlebar, 0, 60); waddstr(titlebar, date_time); wrefresh(titlebar); } void refresh_status(char *msg) { char blank[80]; memset(blank, 0x20, sizeof(blank)); wbkgd(statusbar, A_REVERSE); wmove(statusbar, 0, 1); wprintw(statusbar,"☞ "); wmove(statusbar, 0, 4); wprintw(statusbar, blank); wmove(statusbar, 0, 4); wprintw(statusbar, msg); wrefresh(statusbar); } void make_menubar(WINDOW *menubar) { box(menubar, 0,0); wbkgd(menubar, A_REVERSE); wmove(menubar, 1, 5); wattron(menubar, A_REVERSE); waddstr(menubar, "메뉴1"); waddstr(menubar, "(s)"); wmove(menubar, 1, 25); wattron(menubar, A_REVERSE); waddstr(menubar, "메뉴2"); waddstr(menubar, "(t)"); wmove(menubar, 1, 45); wattron(menubar, A_REVERSE); waddstr(menubar, "메뉴3"); waddstr(menubar, "(p)"); wmove(menubar, 1, 65); wattron(menubar, A_REVERSE); waddstr(menubar, "메뉴4"); waddstr(menubar, "(m)"); } void menu_list(WINDOW **items, char **menu, int cnt, int start_col) { int i; items[0]= newwin(cnt+1,19, 3,start_col); box(items[0], ACS_VLINE, ACS_HLINE); for (i =1; i < cnt; i++) items[i]=subwin(items[0], 1, 17, i+3, start_col+1); for (i =1; i < cnt; i++) wprintw((WINDOW *)items[i], "%s",menu[i]); wbkgd(items[1], A_UNDERLINE|A_STANDOUT); wrefresh(items[0]); return; } int scroll_menu(WINDOW **items,int count,int menu_start_col, int index_num) { int key; int selected=1, before = 1; while (1) { halfdelay(100); switch((key=getch())) { case KEY_DOWN: selected=(selected+1) % count; if (selected == 0) selected = 1; break; case KEY_UP: selected=(selected+count-1) % count; if (selected == 0) selected = count - 1; break; case KEY_LEFT: return key; case KEY_RIGHT: return key; case ESCAPE: return -1; case ENTER: return selected; default: return -1; } if (selected != before) { wbkgd(items[before], COLOR_PAIR(0)); wnoutrefresh(items[before]); before = selected; } wbkgd(items[selected],A_REVERSE); wnoutrefresh(items[selected]); doupdate(); } } void delete_menu(WINDOW **items, int count) { int i; for (i = 0; i < count; i++) delwin((WINDOW *)items[i]); } int check_quit() { WINDOW *check; int key; check = newwin(3, 30, 10, 15); wmove(check, 1, 4); wprintw(check, " Exit program (y/n) ? "); box(check, ACS_VLINE, ACS_HLINE); refresh(); key = wgetch(check); delwin(check); if (key == 'y') return 1; else return 0; } /* 사용자가 선택할 수 있는 메뉴의 갯수는 10개보다 작다는 가정하에 작업. * key 입력값은 항상 '0'보다 큰 값들이 발생한다고 가정. */ int move_menu(int presel, int key, WINDOW **menu_items) { int sitem = key; int before_pos = '0'; while (sitem > '0') { switch(sitem) { case KEY_RIGHT: if (before_pos < '4' && before_pos >= '1') sitem = before_pos + 1; else if (before_pos == '4') sitem = '1'; else sitem = 0; break; case KEY_LEFT : if (before_pos > '1' && before_pos <= '4') sitem = before_pos - 1; else if (before_pos == '1') sitem = '4'; else sitem = 0; break; case '1': case 's': before_pos = '1'; menu_list(menu_items, seq_item, 6, 5); sitem = scroll_menu(menu_items, 6, 5, 0); delete_menu(menu_items, 6); if(sitem < 10 && sitem >= 0) return 100+sitem; break; case '2': case 't': before_pos = '2'; menu_list(menu_items, tr_item, 5, 25); sitem = scroll_menu(menu_items, 5, 20, 0); delete_menu(menu_items, 5); if(sitem < 10 && sitem >= 0) return 200+sitem; break; case '3': case 'p': before_pos = '3'; menu_list(menu_items, proc_item, 5, 45); sitem = scroll_menu(menu_items, 5, 40, 0); delete_menu(menu_items, 5); if(sitem < 10 && sitem >= 0) return 300+sitem; break; case '4': case 'm': before_pos = '4'; menu_list(menu_items, mng_item, 5, 60); sitem = scroll_menu(menu_items, 5, 60, 0); delete_menu(menu_items, 5); if (sitem == 2) { sitem = 'q'; break; } if(sitem < 10 && sitem >= 0) return 400+sitem; break; case 'q': if( check_quit() ) end_screen(); default: //usleep(100); return presel; } touchwin(stdscr); refresh_title(); refresh(); } return presel; } int main(int argc, char **argv) { WINDOW *menu_items[10]; int key; int row, col; int sel; Setsigfatal (); init_screen(); titlebar = subwin(stdscr, 1, 80, 0, 0); menubar = subwin(stdscr, 3, 80, 1, 0); dataview = subwin(stdscr, 36, 80, 4, 0); statusbar = subwin(stdscr, 1, 79, 40, 1); getmaxyx(stdscr,row,col); if (row < 40 || col < 80) { refresh_status("터미널의 사이즈가 너무 작습니다"); end_screen(); return 0; } refresh_title(); make_menubar(menubar); refresh_status("메뉴를 선택하세요"); refresh(); while(1) { halfdelay(100); key = getch(); if ( ( key == 'q' || key == ESCAPE ) && check_quit() ) break; if ( key != KEY_UP && key != KEY_DOWN && key != ERR) sel = move_menu(sel, key, menu_items); switch((int)sel/100) { case 1: break; case 2: break; case 3: break; case 4: break; default: refresh_status("메뉴를 선택하세요"); break; } touchwin(stdscr); refresh_title(); refresh(); } end_screen(); return 0; }
Forums:
오랜만에 익숙한 코드를 봤네요.
한참 자체한글 열풍이 불고 있을 당시에 몇몇 책에서 메뉴와 관련된 함수들이나 화면제어에
관련한 소스들이 있었고 몇몇분들이 통신에 자신들이 만든 소스를 올려놓으셨지만 결국
쓰기편한건 자신이 만든 방법이었었죠.
저도 나름 머리를 쓴다고 범용적인 메뉴를 만들기는 했었는데 소스를보니 그때 생각이
나네요. 어딘가 찾아보면 플로피 디스크에 메뉴에 관련된 소스가 있을텐데 요즘은 귀찮은것이
많네요. 예전에는 엄청 부지런했었다고 생각하는데... :-)
그나저나 #include에 관련된 코드가 깨져보이네요. '<'나 '>'는 HTML에서도 사용되는
코드라서 '& l t ;'나 '& g t ;'(물론 공백이 없어야합니다. :-))이런식으로 표시를
해줘야하는데...
------------------------------
좋은 하루 되세요.
------------------------------
좋은 하루 되세요.
와<code></code>는
와
는 다릅니다.
글 입력 상자 바로 밑에 "입력형식" 링크가 존재합니다.
시간나면 호기심으로라도 한번 눌러보세요.
OTL
수고하셨습니다.
다음에 유용하게 써 먹을 수 있겠군요!!!
---------------------------------------------
svn + trac + my project --> success ???
---------------------------------------------
---------------------------------------------
git init
git add .
git commit -am "project init"
---------------------------------------------
컴파일 한번
컴파일 한번 해보려니깐...에러 발생입니다
libncurses5-dev libncurses5 두개 패키지를 apt-get으로 설치했구요...
tp = localtime(&tloc); 가 93줄 인데..에러 날것이 있었나요? 이상하네요
그리고 strftime도 없을껏 같은데...씨! 를 잘 모르니...ㅠㅠ
소스에 #include
소스에
#include <time.h>
붙여서(순전히 통밥으로 찍었습니다....) 컴파일은 성공했지만프로그램을 실행하니 아무것도 안뜨고 그냥 프롬프트로 나오네요..
무언가 화면에서 실행되어야 하는것 아닌가요?
추가 #include
추가
삭제
main함수에 추가
빌드
그리고 창의 크기를 80x40 이상으로...
다 덤벼! 다 받아줄께!!
다 덤벼! 다 받아줄께!!
doodoo@doodoo:~$ !cc cc -o
doodoo@doodoo:~$ !cc
cc -o cu cu.c -lncursesw
doodoo@doodoo:~$ ls -l cu*
-rwxr-xr-x 1 doodoo doodoo 18540 2008-12-18 10:24 cu
-rw-r--r-- 1 doodoo doodoo 9478 2008-12-18 09:40 cu.c
doodoo@doodoo:~$
doodoo@doodoo:~$ ./cu
doodoo@doodoo:~$
여전히 아무것도 안나오고 프롬프트만 나오는 군요...
doodoo@doodoo:~$ ldd ./cu
linux-vdso.so.1 => (0x00007fff48bfe000)
libncursesw.so.5 => /lib/libncursesw.so.5 (0x00007f95406de000)
libc.so.6 => /lib/libc.so.6 (0x00007f954037c000)
libdl.so.2 => /lib/libdl.so.2 (0x00007f9540178000)
/lib64/ld-linux-x86-64.so.2 (0x00007f9540925000)
doodoo@doodoo:~$
libncursesw.so.5 가 걸려있는건 맞는것 같은데...흠....
혹시 바이너리 파일 사이즈좀 알려 주실수 있나요?
터미널 사이즈가
터미널 사이즈가 작으면 아무것도 안나오고 프롬프트만 나오더군요.
----------
http://sakuragi.org
----------
http://sakuragi.org
그랬었군요...ㅠㅠ 감
그랬었군요...ㅠㅠ
감사합니다...
Thanks for the code. It was
Thanks for the code. It was very useful. By the way, there is quite a lot of good information at shared files SE http://www.sharedshares.com .
댓글 달기