[ncurses] 2. 원하는 위치에 출력하기, Window 활용 함수들

원하는 위치에 글자를 출력할 수 있도록 하는 move 류 함수들과, Window를 활용하기 위한 기초 함수들을 알아봅니다.


커서 이동: move 함수

ncurses를 사용하는 큰 이유 중 하나가 터미널 상에 원하는 위치에 원하는 문자를 출력할 수 있게 해주는 점입니다. 터미널 상에서의 커서 이동은 move와 그 류의 함수들을 사용합니다.

1. move

제일 먼저, 커서의 이동을 위한 함수는 move()입니다. 인자는 순서대로 커서를 놓을 Y좌표, X좌표입니다.

move(5, 7);

이렇게 호출하면 커서는 stdscr의 5번째 줄, 7번째 글자 칸에 위치하게 됩니다.

ncurses의 대부분의 함수가 그렇듯이, move 함수도 wmove() 함수를 짝으로 가지고 있습니다. 그리고 자연스럽게 wmove 함수에는 윈도우가 인자로 들어갑니다.

wmove(win, 2, 3);

이 함수는 win 윈도우 내의 2번째 줄, 3번째 칸에 커서를 위치시킵니다.

stdscr도 윈도우이므로, 다음 두 문장은 같은 동작을 수행합니다.

move(5, 7);
wmove(stdscr, 5, 7);

커서를 원하는 위치에 놓은 후 문자열을 출력해야 할 때가 있습니다. move 함수를 이용하면 쉽게 할 수 있습니다.

#include <ncurses.h>

int main(void){
    initscr();
    printw("0, 0");
    move(5, 5);
    printw("5, 5");
    refresh();
    getch();
    endwin();
}

커서가 이동되어 출력된 것을 볼 수 있습니다.

2. mvprintw

moveprintw를 합쳐놓은 함수가 있습니다. 바로 mvprintw() 함수입니다. 보통 함수 이름 앞에 mv가 붙으면 커서를 이동하는 기능 을 같이 가지고 있습니다. 따라서 아래 두 코드는 같은 동작을 수행합니다.

move(10, 10);
printw("10, 10");
mvprintw(10, 10, "10, 10");

3. mvwprintw

wmovewprintw를 합쳐놓은 함수도 존재합니다. wprintw에 이동 기능이 합쳐쳤으니, 함수 이름은 mvwprintw()입니다. 사용법은 mvprintw()와 동일하고, 윈도우가 인자로 추가로 들어갑니다.

WINDOW * win = newwin(10, 20, 5, 10);
mvwprintw(win, 5, 5, "5, 5 : win");
wrefresh(win);

윈도우를 5, 10 위치에 만들었고, 윈도우 내부에서 5, 5 위치로 커서를 옮겼으므로, stdscr 입장에서 커서는 10, 15 위치에 위치한 후 출력하게 됩니다. 결과를 보시면 실제로 그런 것을 알 수 있습니다. 쉽게 확인하기 위해서 stdscr의 0, 0 위치에 출력을 해 놓았습니다.

Window 활용을 위한 기초 함수들

1. box

box()윈도우의 테두리 를 만들어주기 위한 함수입니다. 지금까지는 윈도우를 만들면 만들었다는 표시가 나지 않았습니다. 하지만 box를 이용하면 ncurses가 스스로 윈도우의 테두리를 만들어 줍니다. box() 함수의 인자로는 윈도우, 세로 테두리를 만들 문자, 가로 테두리를 만들 문자가 순서대로 들어갑니다.

#include <ncurses.h>

int main(void){
    initscr();
    WINDOW * win = newwin(10, 10, 10, 10);
    box(win, '|', '-');        //테두리 만들기
    mvwprintw(win, 1, 1, "Hello");
    box(win, '*', '*');
    refresh();
    wrefresh(win);

    getch();
    endwin();
}

box 함수를 사용하여 테두리를 만들 때 주의할 점은, 테두리 또한 윈도우의 내용에 포함된다는 뜻입니다. 위 코드가 윈도우 내에서 1, 1 위치에 Hello를 출력하는 것을 볼 수 있듯이, 테두리의 내용도 윈도우의 내용에 포함됩니다. 그래서 box를 이용한 테두리 작업 후에는 move 함수를 사용하여 커서를 적절히 옮긴 후 사용해야 합니다.

2. erase, werase

erase()werase()는 윈도우 안의 모든 내용을 공백으로 채워 윈도우를 지우는 기능을 합니다. werase()는 내용을 지울 윈도우를 지정하고, erase()stdscr을 지웁니다.

#include <ncurses.h>

int main(void){
    initscr();
    WINDOW * win = newwin(10, 10, 10, 10);
    box(win, '|', '-');
    mvwprintw(win, 1, 1, "Hello");
    werase(win);
    refresh();
    wrefresh(win);
    getch();
    endwin();
}

box() 함수로 만들었던 테두리 또한 윈도우의 내용이므로, 테두리까지 모두 지워버립니다.

3. mvwin

mvwin() 함수는 윈도우의 위치를 이동시킵니다.

#include <ncurses.h>

int main(void){
    initscr();
    WINDOW * win = newwin(10, 10, 10, 10);
    box(win, '|', '-');
    mvwin(20, 20);        //10, 10 위치에 있던 윈도우를 20, 20으로 이동
    refresh();
    wrefresh(win);
    getch();
    endwin();
}

10, 10 위치에 생성되었던 윈도우를 20, 20 위치로 이동하였습니다.

4. delwin

이름에서 알 수 있듯이, 윈도우 객체를 소멸시키고 메모리 공간을 반환합니다. 하지만 객체만 사라질 뿐이고 스크린에 그린 내용이 바로 사라지지는 않습니다. 따라서 출력된 내용까지 모두 지우고자 할 경우, werase()로 내용을 지운 후 delwin()으로 객체를 지우면 됩니다. 코드로 보겠습니다.

#include <ncurses.h>

int main(void){
    initscr();
    WINDOW * win1 = newwin(10, 10, 10, 10);
    WINDOW * win2 = newwin(10, 10, 25, 25);
    box(win1, '|', '-');
    box(win2, '*', '*');

    refresh();
    wrefresh(win1);
    wrefresh(win2);
    
    /* win1 삭제 */
    werase(win1);
    wrefresh(win1);
    delwin(win1);

    refresh();

    getch();
    endwin();
}

win1의 내용을 모두 지운 후 윈도우를 삭제하였으므로, 화면과 메모리에는 win2만 남게 됩니다.