Wstep do programowania w Ncurses, cz. 1.

G

Guest

Gość
Spis treści:

1. Czym jest Ncurses
2. Początki
3. Wyświetlanie znaków
4. Kolory


----------------------------------------------------------------

1. Czym jest Ncurses.

Nazwa biblioteki Ncurses (New Curses) pochodzi od starszej jej wersji - Curses (klątwa). Biblioteka Curses była dawniej wykorzystywana do obsługi pamięci ekrany oraz terminala. Po jakimś czasie proste funkcje Curses już nie wystarczały i powstała jej nowsza, udoskonalona i bardziej rozbudowana wersja.
W Linuksie, w przeciwieństwie do systemu DOS, dane wypisywane na ekranie są zarządzane przez obsługujący je terminal. Biblioteka Ncurses pozwala w bardzo prosty sposób kontrolować zarówno terminal jak i obsługę klawiatury. Dzięki niej, program napisany w Ncurses może być bez problemów przenoszony między rożnymi systemami uniksowymi oraz rożnymi typami terminali. Ncurses sama przystosowuje się do danego terminala niezależnie od jego typu.
Do czego może nam sie to przydać? Przy pomocy Ncurses możemy bez problemów tworzyć programy pełno ekranowe działające w trybie tekstowym, zawierające ramki, dodatkowe okna, kolory, możemy dowolnie przesuwać kursor na wskazaną pozycję. Dodatkową zaletą Ncurses jest sposób zarządzania pamięcią ekranu. Każda uruchamiona funkcja najpierw jest wykonywana, a dopiero kiedy będzie gotowa, zostaje wyświetlona na ekranie. Dzięki temu taki program bez problemów działa na każdym komputerze, bez względu na szybkość procesora.
Biblioteka Ncurses posiada także bardzo rozwinięte funkcje sterujące ekranem oraz obsługą klawiatury. Możemy dzięki temu w prosty sposób kontrolować klawisze funkcyjne, kursora, itp.
Ten artykuł będzie tylko wprowadzeniem do programowania przy użyciu Ncurses, ale możliwości tej biblioteki są o wiele większe.

----------------------------------------------------------------

2. Początki

Głównym elementem programu pisanego w Ncurses jest jego główne okno. Aby je utworzyć, zawsze na poczatku programu musimy je zainicjować:

WINDOW *initscr();

Funkcja ta zwraca nam indentyfikator danego okna, ale w przypadku głównego okna jest to zawsze stdscr. Standardowe okno stdscr jest zawsze oknem pełno ekranowym. Możemy mieć dowolną liczbę okien, ale o tym później.
Jeśli zainicjowaliśmy okno to na pewno będzie trzeba je na koniec programu (lub przed użyciem funkcji system()) wyłączyć:

int endwin();

Dzięki temu możemy już napisać najprostszy program przy użyciu Ncurses:

/* intro.c */
#include <ncurses.h>

int main()
{
initscr();
endwin();
return 0;
}


Oczywiście, program ten nic poza uruchomieniem i wyłączeniem okna nie robi. :)
Kompilujemy go w ten sposób:

cc intro.c -o intro -lncurses -O2

----------------------------------------------------------------

3. Wyświetlanie znaków

Pisząc program w standardowych bibliotekach C na pewno korzystałeś z funkcji typu printf(), fprintf(). W Ncurses musisz o nich zapomnieć, ponieważ Ncurses nie kontroluje wyników i zwracanych wartości przez funkcje nie pochodzące z tej biblioteki. Poza tym Ncurses ma także kilka bardzo dobrych funkcji umożliwiających wyświetlanie znaków i łancuchów na ekranie. Między innymi takie:

int addch(chtype znak);
int waddch(WINDOW *okno, chtype znak);
int mvaddch(int y, int x, chtype znak);
int mvwaddch(WINDOW *okno, iny y, int x, chtype znak);

Teraz wytłumaczenie... Funkcja addch() wstawia znak w aktualnej pozycji kursora, funkcja waddch() wstawia znak w określonym oknie, mvaddch() wstawia znak w określonej pozycji kursora, a mvwaddch() tak samo jak poprzednio, ale dodatkowo w wybranym oknie.
Typ znaku chtype nie jest typem char. Jest to 16 bitowy typ zmiennej zawierający znak oraz jego atrybuty (np. kolor). Jeśli użyjemy typu char, atrybuty zostaną wyłączone.
Jeśli już wiemy jak wstawiać znaki, przydałaby się także funkcja do ustawiania pozycji kursora na ekranie. Taką funkcją jest:

int move(int y, int x);

Zmienne 'y' oraz 'x' oznaczają pozycje kursora (liczba pikseli).
Aby odczytać wartość z ekranu, możemy użyć funkcji:

chtype inch(void);

Funkcja inch() zwraca wartość zmiennej chtype z okna stdscr. Podobnie jak poprzednie funkcje, inch() może być także używana z przedrostkami, czyli: winch(), mvinch(), mvwinch(). Działają na tej samej zasadzie co funkcje wstawiające znak.
Wyświetlanie całych łancuchów znaków też jest bardzo proste. Użyjemy do tego funkcji:

int addstr(const char *tekst);

I znowu, jak w poprzednich przypadkach, funkcja ta ma swoje odpowiedniki z przedrostkami, a więc także: mvaddstr(), waddstr(), mvwaddstr().

Na tym etapie możemy już napisać prosty program, który wyświetli nam jakiś tekst. Niech będzie słynne już "Hello World!". ;-)

/* hello.c */
#include <ncurses.h>

int main()
{
initscr();
addstr("Hello World!");
endwin();
return 0;
}


Kompilujemy nasz program i uruchamiamy. Pewnie pomyślisz, że coś jest nie tak, bo nic nie zobaczyłeś. To jest właśnie efekt sprytnego buforowania tekstu przez Ncurses. Dzięki temu nawet jeśli uruchamiasz program na wolnym terminalu, nic nie tracisz bo najpierw cały tekst jest buforowany, a dopiero wtedy wyświetlany na ekranie.
Oczywiście na to także jest sposób - funkcja refresh(), która odświeża ekran i wyświetla wszystko, co do tej pory zostało zrobione. Prototyp funkcji refresh() wygląda tak:

int refresh(void);

Dodatkowo aby wszystko było ładnie widać, dodamy funkcję getch(), która zatrzyma program do naciśnięcia przez nas jakiegoś klawisza.

/* hello2.c */
#include <ncurses.h>

int main()
{
initscr();
addstr("Hello World!");
refresh();
getch();
endwin();
return 0;
}


Trochę lepiej, prawda? :)

----------------------------------------------------------------

4. Kolory

Na początku pisałem o tym, że Ncurses pozwala na używanie kolorów. Teraz opisza jak ich używać. Do tego celu będziemy używali bardziej rozbudowanej funkcji, jaką jest printw(). Jej składnia jest bardzo podobna do na pewno znanej wam printf(). Ale dlaczego nie powinniśmy użyć printf()? Z prostego powodu - ekran działający na Ncurses nie jest powiadamiany o użytych funkcjach z poza biblioteki ncurses, co może doprowadzić do zniszczenia naszego ekranu.
No ok, ale co z tymi kolorami? Aby ich używać, musimy najpierw je zainicjować. Służy do tego funkcja init_pair():

int init_pair(short pair, short kolor, short tlo);

Funkcja ta inicjuje wewnętrzną tablicę artybutów tekstu, gdzie 'pair' oznacza identyfikator edytowanej pary, 'kolor' oznacza kolor czcionki, natomiast 'tlo' kolor tła ekranu.
Mamy dostępne między innymi takie kolory:

COLOR_BLACK
COLOR_RED
COLOR_BLUE
COLOR_GREEN
COLOR_YELLOW
COLOR_MAGENTA
COLOR_CYAN
COLOR_WHITE
COLOR_ORANGE
itd...

Niestety to jeszcze nie wystarczy do wypisania kolorowego tekstu bo musimy jeszcze dany atrybut uczynic atrybutem bierzącym. Służy do tego funkcja:

int attrset(int attrs);

Parametr 'attrs' jest atrybutem, którego chcemy używać. Jeśli ma to być para kolorów to należy ją przekonwertować na postać atrybutu. Robimy to makrem:

attr_t COLOR_PAIR(n);

gdzie 'n' jest numerem naszej pary kolorów.
Ustawianie kolorów oraz atrybutów mamy juz za sobą. Teraz trzeba tylko powiadomić nasz terminal, że będziemy używać kolorów:

int start_color(void);

To już praktycznie wszystko. Możemy teraz udoskonalić nasz program 'hello', aby wyświetlał nam tekst w kolorze.

/* hello3.c */
#include <ncurses.h>

int main()
{
initscr();
start_color();
init_pair(1, COLOR_RED, COLOR_GREEN);
attrset(COLOR_PAIR(1));
printw("Hello World!n");
printw("Tekst w kolorze %d, tło w kolorze: %d", COLOR_RED, COLOR_GREEN);
refresh();
getch();
endwin();
return 0;
}

Kompilujemy, uruchamiamy i cieszymi się naszym pierwszym programem w Ncurses z wykorzystaniem kolorów. :)
Teraz pojawia się kolejne pytanie: co jeśli terminal nie może wyświetlać kolorów? Wtedy możemy użyć standardowych atrybutów, takich jak pogrubienie, miganie, podkreślenie, itp. Są to:

A_NORMAL - normalny atrybut, biały tekst na czarnym tle
A_UNDERLINE - atrybut podkreślenia
A_REVERSE - atrybut zamienia kolor tła na kolor znaku i odwrotnie
A_BLINK - atrybut migotania
A_BOLD - atrybut pogrubienia
A_INVIS - atrybut niewidzialności
A_CHARTEXT - atrybut pozwala na wyświetlenie dowolnych znaków, łącznie z "high-ASCII"

Atrybutów używamy tak samo jak pozostałych, a więc np.:

attrset(A_BOLD);

Do już ustawionych atrybutów możemy dodawać nowe lub usuwać już istniejące. Służą do tego funkcje:

int attron(int attrs);
int attroff(int attrs);

Na przykład jeśli chcemy, aby nasz tekst był jednocześnie pogrubiony oraz podkreślony:

attrset(A_BOLD);
addstr("Tekst pogrubiony.");
attron(A_UNDERLINE);
addstr("Tekst pogrubiony i podkreślony.");


Na zakończenie przydałoby się jeszcze wspomnieć i bardzo przydatnej funkcji jaką jest:

bool has_colors(void);

Funkcja ta zwraca wartość TRUE (prawda) jeśli terminal jest kolorowy, lub FALSE (fałsz) jeśli taki nie jest. W takim przypadku powinniśmy użyć predefiniowanych atrybutów zamiast kolorowych.
Przykładowe użycie funkcji has_colors() może wyglądać tak:

/* test_colors.c */
#include <ncurses.h>

int main()
{
bool kolor;

initscr();
if((kolor = has_colors()) == FALSE)
{
attrset(A_BOLD);
addstr("Twój terminal nie może wyświetlać kolorów!");
refresh();
getch();
endwin();
return 1;
}

start_color();
it_pair(1, COLOR_RED, COLOR_GREEN);
attrset(COLOR_PAIR(1));
printw("Twój terminal może wyświetlać kolory.");
refresh();
getch();
endwin();
return 0;
}


----------------------------------------------------------------

I to by było na tyle jeśli chodzi o kolory w Ncurses i część pierwszą tego artykułu.
Jeśli kogoś zainteresował ten artykuł oraz programowanie przy użyciu biblioteki Ncurses to zapraszam za jakiś czas na część drugą. ;-)

------
RAVEN ([email protected])
 
Do góry Bottom