Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Linux, Systemprogrammierung C C++ C/C++ ANSI C Linux Linuxsystemprogrammierung Semigrafik curses.h ncurses curses Linuxsystemprogrammieren Semigrafik curses.h ncurses curses 10. Semigrafik (curses.h)
Damit überhaupt das Scrolling aktiviert wird, müssen Sie das Scrolling zuerst auch mit scrollok() aktivieren.
int scroll(WINDOW *win);
Mit der Funktion scroll() schieben Sie den, durch den Parameter win angegeben Bildschirm, um eine Zeile nach oben. Wenn stdscr angegeben wird, wird der ganze Bildschirm gescrollt.
int scrl(int anzahl);
Mit scrl() schieben Sie den Bildschirm mittels anzahl>0, anzahl Zeilen nach oben und mit anzahl<0, anzahl Zeilen nach unten. Mit der Funktion setscrreg() (siehe Kapitel zuvor) können Sie den Scrollbereich definieren.
Nun wollen wir ein etwas umfangreicheres Beispiel schreiben, wo die Funktionen scroll() und scrl() und andere schon kennen gelernte Funktionen vorkommen. Wir lassen ein kleines Raumschiff durch Sterne gleiten. Mit den Cursortasten Pfeil nach Rechts und Pfeil nach Links, können Sie das Raumschiff steuern. Mit q beenden Sie das Programm ...
#include <curses.h> #include <stdlib.h> /*'q'*/ #define QUIT 113 /* '<-'*/ #define LEFT 260 /* '->'*/ #define RIGHT 261 int main() { int x=40,zufall, c,i; srand(79); initscr(); keypad(stdscr,TRUE); /*Cursor und Funktionstasten*/ noecho(); /*keine Ausgabe*/ scrollok(stdscr,TRUE); /*Scrolling ein*/ scroll(stdscr); while(c!=QUIT) { scrl(1); /*Eine Zeile runter scrollen*/ for(i=0;i<5;i++) { zufall=rand()%79; mvaddch(20,zufall,'*'); mvprintw(0,0,"'q' drücken für Quit | Taste für Start | " "<- nach links -> nach rechts"); } c=getch(); halfdelay(3); switch(c) { case LEFT : if(x<1) x=79; else x--; break; case RIGHT: if(x>79) x=1; else x++; break; default : break; } mvdelch(9,x+2);mvdelch(9,x+1);mvdelch(9,x); mvdelch(9,x-1);mvdelch(9,x-2); mvaddch(10,x-1,ACS_LLCORNER); mvaddch(10,x+1,ACS_LRCORNER); mvaddch(10,x,ACS_TTEE); } endwin(); return 0; }
So siehts aus:
Jetzt wollen wir uns ansehen, wie wir einige Attribute setzen können. Folgende Funktionen stehen uns zur Verfügung ...
int attroff(int attribut);
Mit dieser Funktion wird ein Attribut das gesetzt war, deaktivieren. Beispielsweise ...
attroff(A_BLINK);
Damit wird das Blinken eines Textes oder Zeichens deaktiviert.
int attron(int attribut);Die Funktion attron() ist das Gegenstück zur Funktion attroff() und dient zur Aktivierung eines Attributes. attron() eignet sich zum Beispiel für einen String der schon ein Attribut bekommen hat, um ein weiteres zu aktivieren.
int attrset(int attribut);
Mit attrset() setzten Sie jedes beliebige Attribut bzw. mehrere davib. z.B. ...
attrset(A_BOLD | A_BLINK); printw("Dieser Text wird FETT und BLINKEND angezeigt");
Folgende Attribute können Sie verwenden:
Attribut | Bedeutung |
A_NORMAL | Normale Darstellung |
A_STANDOUT | Zeichen stärkste Helligkeit |
A_UNDERLINE | Zeichen unterstreichen |
A_REVERSE | Invers |
A_BLINK | blinken |
A_DIM | Zeichen werden dunkler |
A_BOLD | Fette Zeichen |
A_PROTECT | Geschützter Modus |
A_INVIS | Unsichtbar |
A_ALTCHARSET | Umschalten auf Zeichengrafik |
A_CHARTEXT | Macht aus dem 32Bit Wert (chtype) durch eine &-Verknüpfung einen 8Bit-Wert (ASCII) |
Die Funktion COLOR_PAIR(n) setzt Farbenpaare zusammen (Hintergrund und Schrift)
Bevor Sie Farbe für ein Programm verwenden werden, müssen Sie erst mal testen, ob überhaupt Farben verfügbar sind ...
bool has_colors();
Dies schreiben Sie am besten folgendermaßen ...
if(has_colors==TRUE) /*Wir haben Farbe*/ else /*Wir haben keine Farbe*/
Ein weitere Abfrage zu den Farben, wäre die Funktion ...
bool can_change_colors(void);
Damit können Sie Abfragen, ob Sie die Farben vom Programm aus ändern können.
Falls Sie Farbe zur Verfügung haben (has_colors==TRUE), müssen Sie nach dem Aufruf von initscr() die Funktion ...
int start_color(void);
...aufrufen. Mit start_color() initialisieren Sie die Farben und gleichzeitig die globale Variablen COLORS und COLOR_PAIRS. COLOR_PAIRS stellt ein Farbenpaar da, aus Hintergrund und Schriftfarbe. Folgende Farben sind in der Headerdatei curses.h folgendermaßen definiert ...
#define COLOR_BLACK 0 #define COLOR_RED 1 #define COLOR_GREEN 2 #define COLOR_YELLOW 3 #define COLOR_BLUE 4 #define COLOR_MAGENTA 5 #define COLOR_CYAN 6 #define COLOR_WHITE 7
int init_pair(short paarnummer, int zeichen, int hintergrund);
Mit der Funktion init_pair() legen Sie eine Paarnummer fest, die Sie dann mit der Funktion attrset() ausgeben können. z.B. ...
init_pair(1,COLOR_RED,COLOR_GREEN);
Damit legen Sie ein Paar mit roter Schrift und grünem Hintergrund fest. Das Paar hat die Nummer 1. Dies setzten Sie jetzt wie folgt in der Praxis ein ...
attrset(COLOR_PAIR(1)); printfw("Dieser Text wird mit roten Zeichen auf grünen Hintergrund ausgegeben.");
...oder so ...
init_pair(2,COLOR_BLUE,COLOR_BLACK); attrset(A_BOLD|COLOR_PAIR(2)); printw("Dieser Text wird mit fetter blauer Schrift " "und schwarzem Hintergrund ausgegeben.");
Mit init_pair() können Sie insgesamt 64 verschiedene Farbkombinationen festlegen. Nur das Farbpaar mit dem Index 0 (COLOR_PAIR(0)) kann nie geändert werden. Dieser Wert entspricht immer weissen Text auf schwarzem Hintergrund.
Um z.B. herauszufinden, welche Farbe in einem Farbpaar definiert wurde, gibt es die Funktion ...
int pair_content(short paarnummer, short *zeichenfarbe, short *hintergrundfarbe);
Wozu soll das gut sein? Es gibt eine Möglichkeiten alle Farbpaare auf einmal zu definieren...
int farbe1,farbe2,i=1; if(has_color==TRUE) { start_color(); for(farbe1=COLOR_WHITE;farbe1>=COLOR_BLACK;farbe1--) //WHITE=7;BLACK=0 for(farbe2=COLOR_BLACK; farbe2<=COLOR_WHITE; farbe2++) init_pair(i++,farbe1,farbe2); }
Damit werden alle 64 Farbenpaare auf einmal definiert. Um jetzt zu wissen, welchen Farbwert das Paar 50 hat, brauchen Sie nur ...
pair_content(50,&zeichenfarbe,&hintergrundfarbe);
...an die Adressen der Variablen zeichenfarbe und hintergrundfarbe übergeben.
Jetzt wollen wir die Attribute und Farben auf das Programm mit dem Raumschiff durchs Weltall loslassen ...
#include <curses.h> #include <stdlib.h> /* 'q' */ #define QUIT 113 /* '<-' */ #define LEFT 260 /* -> */ #define RIGHT 261 int main() { int x=40,zufall, c,i,vor,hint; srand(79); initscr(); if(has_colors()==TRUE) start_color(); else exit (0); keypad(stdscr,TRUE); /*Cursor und Funktionstasten*/ noecho(); /*keine Ausgabe*/ scrollok(stdscr,TRUE); /*Scrolling ein*/ scroll(stdscr); init_pair(1,COLOR_YELLOW,COLOR_BLACK); /*Farbenpaar Nummer 1*/ init_pair(2,COLOR_CYAN,COLOR_CYAN); /*PaarNummer 2*/ init_pair(3,COLOR_GREEN,COLOR_BLACK); /*Farbenpaar Nummer 3*/ init_pair(4,COLOR_BLACK,COLOR_GREEN); /*Farbenpaar Nummer 4*/ while(c!=QUIT) { scrl(1); /*Eine Zeile runter scrollen*/ for(i=0;i<5;i++) { zufall=rand()%79; attrset(A_DIM|COLOR_PAIR(1)); /*Sterne dunkel ausgegeben*/ mvaddch(20,zufall,'*'); attrset(A_UNDERLINE|A_BOLD|COLOR_PAIR(4)); /*Blinkend*/ mvprintw(0,0,"'q' drücken für Quit | Taste für Start | " "<- nach links -> nach rechts"); } c=getch(); halfdelay(3); switch(c) { case LEFT : if(x<1) x=79; else x--; break; case RIGHT: if(x>79) x=1; else x++; break; default : break; } mvdelch(9,x+2);mvdelch(9,x+1);mvdelch(9,x); mvdelch(9,x-1);mvdelch(9,x-2); attrset(A_BOLD|COLOR_PAIR(2)); /*Raumschiff fette Schrift*/ mvaddch(10,x-1,ACS_LLCORNER); mvaddch(10,x+1,ACS_LRCORNER); attrset(A_BOLD|COLOR_PAIR(3)); mvaddch(10,x,ACS_TTEE); } /*Ende while()*/ endwin(); return 0; }
So siehts aus:
Jetzt wollen wir noch ein wenig die Fensterroutinen durchnehmen.
Fensterroutinen funktionieren genauso wie schon die im Kapitel zuvor besprochenen Funktionen, nur wird Ihnen noch ein Zeiger auf die WINDOW-Struktur übergeben. Zusätzlich bekommen die Funktionen, die sich auf das Fenster beziehen, noch das Präfix 'w' z.B. aus printw wird ...
wprintw(WINDOW *win, char *format, ...);
...oder aus mvprintw() wird...
mvwprintw(WINDOW *win, int y, int x, char *format, ...);
...u.s.w. Funktionen mit dem mv-Präfix, werden somit zu mvw-Präfixen. Einfach bei allen Funktionen die Sie kennen zusätzlich das w oder mvw und die WINDOW-Struktur übergeben. Falls Sie sich nicht sicher sind, schauen Sie sich einfach die entsprechende man-Pages dazu an. Zum Beispiel geben Sie 'man getch' ein und sie werden auch die Routine für wgetch für Fenster finden. Da alle bisher erlernten Funktionen somit genauso funktionieren, erspare ich mir die genauere Beschreibung dazu.
WINDOW *newwin(int anzahl_zeilen, int anzah_Spalten, int cursor_y, int cursor_X);
Mit newwin erstellen Sie ein neues Fenster mit anzahl_zeilen und anzahl_spalten. Dies machen Sie mit ...
stdscr=newline(anzahl_zeilen,anzahl_spalten,0,0) int box(WINDOW *win, chtype zeichenvertikal, chtype zeichenhorizontal);
Mit der Funktion box() können Sie einen Rahmen um das Fenster win legen. z.B. ...
//Fenster mit dem Namen Fenster 10 Zeilen und 79 Spalten gross fenster=newwin(10,79,0,0); //Linien um den Fensterbereich ziehen eine Box box(fenster,ACS_VLINE,ACS_HLINE);
Die ACS_ - Zeichen und den Datentyp chtype haben Sie ja bereits kennen gelernt.
Gleiches wie mit der Funktion box(), können Sie auch mit den folgenden Funktionen machen ...
int hline(chtype zeichen, int n); int vline(chtype zeichen, int n);
WINDOW *dupwin(WINDOW *win);
Mit der Funktion dupwin() können Sie eine Kopie des WINDOW win machen. Beispielsweise ...
fenster2=dupwin(fenster1);
Wenn man dieses Fenster nicht mehr benötigt, so muss man dies mit der Funktion ...
int delwin(WINDOW *win);
...wieder freigeben. Beispiel ...
delwin(fenster2);
Wenn Sie ein Fenster verschieben wollen, machen sie dies mit dieser Funktion ...
int mvwin(WINDOW *win, int y, int x);
Als Ausgangspunkt wird die linke obere Ecke genommen. Diese ermitteln Sie, falls nicht bekannt, mit der Funktion ...
void getbegyx(WINDOW *win, int y, int x);
Achtung auch hier gilt, nicht den Adressoperator '&' für die Variablen y und x einzusetzen. Wollen Sie Beispielsweise den Bildschirm von der aktuellen Position drei Zeilen tiefer und zehn Spalten nach rechts setzten, dann macht man dies so ...
int y,x; getbegyx(fenster1,y,x); mvwin(fenster1,y+3,x+10);
Um die gesamte Größe eines Fensters zu ermitteln, gibt es die Funktion ...
int getmaxyx(WINDOW *win, int y, int x);
Auch hier benötigen Sie für die Variablen y und x keinen Adressoperator.
Manchmal wenn Sie die Funktion refresh() benötigen, um den gesamten Fensterinhalt neu zu zeichnen, benötigen Sie eine Funktion, die ein Fenster als verändert markiert. Denn, refresh() zeichnet nur dann neu, wenn sich auf dem Bildschirm auch etwas verändert hat. Dies können Sie mit dieser Funktion machen ...
int touchwin(WINDOW *win);
Den Standardbildschirm stdscr können Sie nun mittels refresh neu zeichnen. Bei anderen Fenstern benötigen Sie folgende Funktion ...
wrefresh(WINDOW *win);
Falls Sie überprüfen wollen, ob sich auf dem Fenster etwas verändert hat, können Sie dies mit der Funktion ...
int is_wintouched(WINDOW *win);
...abfragen. Zum Beispiel ...
if(is_wintouched(fenster1)) //wurde Fenster verändert wrefresh(fenster1); //dann zeichne neu else //ansonsten... { touchwin(fenster1); //tu so wie wenn das Fenster verändert wurde wrefresh(fenster1); //und zeichne dann neu }
int overwrite(const WINDOW *quelle, WINDOW *ziel); int overlay(const WINDOW *quelle, WINDOW *ziel);
Diese beiden Funktionen kopieren (nur) die Zeichen vom Fenster quelle ins Fenster ziel. Der Unterschied der beiden Funktionen liegt daran, dass overlay() kein Leerzeichen mitkopiert.
Jetzt wollen wir noch ein Programm schreiben, dass die meisten der Fensterfunktionen selbsterklärend darstellen soll. Das Programm hält nach jedem kleinen Beispiel an. Bitte drücken sie eine Taste um zur nächsten Funktion im Programm zu springen. ...
#include <curses.h> #define schwarz 0 #define rot 1 #define gruen 2 #define gelb 3 #define blau 4 #define lila 5 #define hblau 6 #define weiss 7 /*zeigt uns alle möglichen Farbpaare an*/ void show_all_pairs() { int farbe1,farbe2,i=1,c; mvprintw(1,1,"Darstellung aller Farbenpaare : \n"); if(has_colors()==TRUE) { start_color(); for(farbe1=weiss; farbe1>=schwarz; farbe1--) for(farbe2=schwarz; farbe2<=weiss; farbe2++) { init_pair(i,farbe1,farbe2); attrset(COLOR_PAIR(i)); printw(" %d ",i++); } } noecho(); c=getch(); } /*Erzeugen ein neues Fenster mit sämtlichen Attributen*/ WINDOW *create_new_window(WINDOW *neues_fenster, int zeilen, int spalten, int hinterg, int vorderg, int begin_y, int begin_x, char *text, int text_y, int text_x) { neues_fenster=newwin(zeilen,spalten,begin_y,begin_x); init_pair(1,hinterg,vorderg); wattrset(neues_fenster,COLOR_PAIR(1)); box(neues_fenster,ACS_VLINE,ACS_HLINE); mvwprintw(neues_fenster,text_y,text_x,text); return neues_fenster; } int main() { WINDOW *fenster1,*fenster2,*fenster3; int y,x,max_y,max_x; initscr(); raw(); keypad(stdscr,TRUE); if(has_colors() == TRUE) start_color(); show_all_pairs(); clear(); refresh(); fenster1=create_new_window(fenster1,11,50,blau,weiss,0,0,"Hallo Welt",5,20); keypad(fenster1,TRUE); wrefresh(fenster1); wgetch(fenster1); fenster2=create_new_window(fenster2,10,50,rot,gruen,11,30,"Fenster 2",1,1); keypad(fenster2,TRUE); wrefresh(fenster2); wgetch(fenster2); mvwprintw(fenster1,5,5,"Wir verschieben Fenster 2 mit mvwin()"); wrefresh(fenster1); wgetch(fenster1); getbegyx(fenster2,y,x); /*Wo ist das Fenster 2 genau*/ touchwin(stdscr); /*stdscr neuzeichnen*/ refresh(); /*Fenster 3 Zeilen tiefer und 20 Spalten nach links.*/ mvwin(fenster2,y+3,x-20); /*Da Fenster 1 nicht verändert wurde und wir neu zeichnen wollen*/ touchwin(fenster1); wrefresh(fenster1); wrefresh(fenster2); wgetch(fenster2); mvwprintw(fenster1,5,5," Wir löschen Fenster 2 mit delwin() "); wrefresh(fenster1); wgetch(fenster1); delwin(fenster2); /*Löscht Fenster 2*/ touchwin(stdscr); refresh(); mvwin(fenster1,0,0); wrefresh(fenster1); wgetch(fenster1); mvwprintw(fenster1,5,5,"Wir kopieren dieses Fenster mit dupwin()"); wrefresh(fenster1); wgetch(fenster1); fenster2=dupwin(fenster1); mvwin(fenster2,12,0); wrefresh(fenster2); wgetch(fenster2); mvwprintw(fenster1,5,1," Fenster 1 wird nun geloescht "); wrefresh(fenster1); wgetch(fenster1); delwin(fenster1); touchwin(stdscr); refresh(); touchwin(fenster2); wrefresh(fenster2); wgetch(fenster2); attrset(COLOR_PAIR(0)); mvprintw(1,1,"Nun wird das letzte Fenster auch noch beendet"); refresh(); wgetch(fenster2); delwin(fenster2); touchwin(stdscr); refresh(); mvprintw(1,1,"Jetzt ist nur noch das Fenster stdscr in Betrieb!"); getch(); endwin(); return 0; }