![]() |
|
|
13.3.5 Attribute und Farben setzen
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| Attribut | Bedeutung |
| A_NORMAL | Normale Darstellung (Standardeinstellung) |
| 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 32-Bit-Wert (chtype) durch eine &-Verknüpfung einen 8-Bit-Wert (ASCII) |
Wenn Sie mit den Farben spielen wollen, müssen Sie überprüfen, ob Farben in dem aktuellen Terminaltyp verfügbar sind. Hierzu wird folgende Funktion verwendet:
#include <curses.h> bool has_colors( void );
Verwenden lässt sich die Funktion recht einfach:
if(has_colors==TRUE) {
// Wir haben Farbe*/
}
else {
// Wir haben keine Farbe
}
Eine weitere Anwendung zu den Farben wäre die Funktion zur Abfrage, ob die Farben des aktuellen Terminaltyps überhaupt verändert werden dürfen:
#include <curses.h> bool can_change_colors(void);
Sofern Ihnen also Farben für den Terminaltyp zur Verfügung stehen, müssen Sie als Nächstes die Farben initialisieren:
#include <curses.h> int start_color(void);
Diese Funktion sollten Sie nach der Funktion initscr() aufrufen. Mit start_color() initialisieren Sie die Farben und gleichzeitig auch die globalen Variablen COLORS und COLOR_PAIRS. COLOR_PAIRS ist ein Farbenpaar, das sich aus dem Hintergrund und der Schriftfarbe zusammensetzt. Folgende Farben sind dabei in der Headerdatei curses.h 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
Um ein Farbenpaar (Schrift und Hintergrundfarbe) festzulegen, wird die folgende Funktion verwendet:
#include <curses.h> int init_pair(short paarnummer, int zeichen, int hintergrund);
Mit der Funktion init_pair() legen Sie mit der Angabe der Zeichenfarbe und der Hintergrundfarbe eine Paarnummer (paarnummer) fest, die Sie dann mit der Funktion attrset() verwenden können, z. B.:
init_pair(1,COLOR_RED,COLOR_GREEN);
Damit legen Sie ein Farbenpaar mit roter Schrift und grünem Hintergrund fest. Das Paar hat die Nummer 1. Dies setzen Sie jetzt wie folgt in die Praxis um:
attrset(COLOR_PAIR(1));
printfw("Dieser Text wird mit roten Zeichen auf grünem"
" Hintergrund ausgegeben.");
/* Eine weitere Farbe wird definiert */
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.");
Die Funktion COLOR_PAIR(n) setzt die Farbenpaare zusammen (Hintergrund und Schrift). Mit init_pair() können Sie gewöhnlich insgesamt 64 (8 * 8) verschiedene Farbkombinationen festlegen. Nur das Farbpaar mit dem Index 0 (COLOR_PAIR(0)) kann nie geändert werden. Dieser Wert entspricht immer einem weißen Text auf schwarzem Hintergrund – und dient für den Fall der Fälle dazu, Ihren Terminal wieder zurückzusetzen.
Wollen Sie ermitteln, welche Farben in einem bestimmten Farbenpaar definiert wurden, dann können Sie folgende Funktion verwenden:
#include <curses.h> int pair_content( short paarnummer, short *zeichenfarbe, short *hintergrundfarbe);
pair_content() eignet sich hervorragend, um mehrere Farbenpaare auf einmal zu definieren, wie der folgende Codeausschnitt demonstrieren soll:
int farbe1,farbe2,i=1;
if(has_color==TRUE) {
start_color();
// WHITE=7 => BLACK=0
for(farbe1=COLOR_WHITE; farbe1>=COLOR_BLACK; farbe1--)
for(farbe2=COLOR_BLACK; farbe2<=COLOR_WHITE; farbe2++)
init_pair(i++, farbe1, farbe2);
}
Damit werden alle 64 Farbenpaare auf einmal definiert. Um jetzt zu ermitteln, welchen Farbwert das Paar 50 hat, müssen Sie die Funktion pair_content() aufrufen:
pair_content(50, &zeichenfarbe, &hintergrundfarbe);
Jetzt befindet sich in der Adresse von zeichenfarbe und in der Adresse von hintergrundfarbe ein entsprechender Farbeintrag des Farbenpaars mit der Nummer 50.
Die Attribute und Farben werden jetzt im Listing des fliegenden Raumschiffs im Weltall eingesetzt.
/* cur11.c */ #include <curses.h> #include <stdlib.h> #define QUIT 113 // 'q' #define LEFT 260 // '<-' #define RIGHT 261 // -> static void print_raumschiff (int x) { mvdelch (9, x + 2); mvdelch (9, x + 1); mvdelch (9, x); mvdelch (9, x - 1); mvdelch (9, x - 2); /*Raumschiff fette Schrift */ attrset (A_BOLD | COLOR_PAIR (2)); mvaddch (10, x - 1, ACS_LLCORNER); mvaddch (10, x + 1, ACS_LRCORNER); attrset (A_BOLD | COLOR_PAIR (3)); mvaddch (10, x, ACS_TTEE); } int main (void) { int x = 40, zufall, c, i; srand (79); initscr (); if (has_colors () == TRUE) start_color (); else exit (EXIT_FAILURE); keypad (stdscr, TRUE); noecho (); scrollok (stdscr, TRUE); scroll (stdscr); // Farbenpaar Nummer 1 init_pair (1, COLOR_YELLOW, COLOR_BLACK); // Paar Nummer 2 init_pair (2, COLOR_RED, COLOR_RED); // Farbenpaar Nummer 3 init_pair (3, COLOR_GREEN, COLOR_BLACK); // Farbenpaar Nummer 4 init_pair (4, COLOR_BLACK, COLOR_GREEN); while (c != QUIT) { scrl (1); for (i = 0; i < 5; i++) { zufall = rand () % 79; // Sterne dunkel ausgegeben attrset (A_DIM | COLOR_PAIR (1)); mvaddch (20, zufall, '*'); attrset (A_UNDERLINE | A_BOLD | COLOR_PAIR (4)); 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; } print_raumschiff (x); } endwin (); return 0; }
Ein Screenshot kann ich mir hierbei ersparen, da dieser ohnehin schwarz-weiß ist.
|
Hinweis Auch in diesem Listing wird davon ausgegangen, dass Sie eine gewöhnliche 80 × 24 cm große Konsole (z. B. VT100) verwenden. Andernfalls kann die Anwendung nicht richtig laufen (es sei denn, Sie passen die Breite der Konsole dem Listing an). |
Fensterroutinen funktionieren genauso wie schon die im Abschnitt zuvor besprochenen Funktionen, nur wird diesen immer ein Zeiger auf eine WINDOW-Struktur übergeben. Zusätzlich bekommen die Funktionen, die sich auf ein bestimmtes Fenster beziehen, noch das Präfix w. Aus printw() wird dann z. B.
wprintw(WINDOW *win, char *format, ...);
und aus den Funktionen mit den mv-Präfixen wird ein mvw-Präfix:
mvwprintw(WINDOW *win, int y, int x, char *format, ...);
Bei allen Funktionen, die Sie bereits kennen, müssen Sie also zusätzlich das w oder mvw und die WINDOW-Struktur verwenden. Falls Sie sich nicht sicher sind, sehen Sie sich einfach die entsprechende Manual Page dazu an. Geben Sie zum Beispiel man getch ein, so werden Sie auch die Routine wgetch(), die sich auf das Fenster bezieht, finden. Da alle bisher beschriebenen Funktionen somit genauso funktionieren, erspare ich mir die genauere Beschreibung dazu.
Um ein weiteres Fenster zu erzeugen, wird die Funktion newwin() verwendet:
#include <curses.h> 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. Zusätzlich können Sie den Cursor gleich an entsprechender y- und x-Position festlegen (0,0 bedeutet die linke obere Seite des neuen Fensters).
Um ein neues Fenster auch ein wenig hervorzuheben, sollten Sie einen Rahmen darum legen. Einen Rahmen um ein bestimmtes Fenster können Sie mit der Funktion box() ausgeben:
#include <curses.h> int box( WINDOW *win, chtype zeichenvertikal, chtype zeichenhorizontal );
Damit legen Sie einen Rahmen um das Fenster, worauf win mit den Zeichen zeichenvertikal und zeichenhorizontal zeigt, die beide vom Typ chtype sind, womit Sie also auch Zeichen jenseits der char-Grenze ausgeben können. Hierzu ein kurzer Codeausschnitt, wie Sie einen Rahmen um ein Fenster legen können:
// Fenster mit dem Namen fenster 10 Zeilen und 79 Spalten groß 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:
#include <curses.h> // n-Zeichen horizontal ab akt. Cursorposition int hline(chtype zeichen, int n); // n-Zeichen vertikal ab akt. Cursorposition int vline(chtype zeichen, int n);
Sie können ein Fenster auch duplizieren. Das erledigen Sie mit der Funktion:
#include <curses.h> WINDOW *dupwin(WINDOW *win); int delwin(WINDOW *win);
Der Rückgabewert von dupwin() ist eine exakte Kopie des Fensters win. Wenn Sie dieses Fenster nicht mehr benötigen, sollten Sie den nicht mehr benötigten Speicherplatz, den dieses Fenster belegt, mit der Funktion delwin() wieder freigeben, z. B.:
// Fenster fenster1 duplizieren fenster2=dupwin(fenster1); ... // Nach vielen Zeilen Code wird die Kopie nicht mehr benötigt delwin(fenster2);
Verschieben können Sie ein Fenster mit der Funktion:
#include <curses.h> int mvwin(WINDOW *win, int y, int x);
Als Ausgangspunkt zum Verschieben wird immer die linke obere Ecke genommen. Diese ermitteln Sie, falls Ihnen diese nicht bekannt ist, mit der Funktion:
#include <curses.h> void getbegyx(WINDOW *win, int y, int x);
Achtung! Auch hier gilt es, 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 setzen, dann funktioniert dies so:
int y,x; ... getbegyx(fenster1,y,x); mvwin(fenster1,y+3,x+10);
Benötigen Sie die gesamte Größe eines Fensters, dann verwenden Sie die Funktion
#include <curses.h> 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. Ein Fenster als verändert markieren können Sie mit der Funktion
#include <curses.h> int touchwin(WINDOW *win);
Der Standardbildschirm stdscr kann nun mittels refresh() neu gezeichnet werden. Bei anderen Fenstern benötigen Sie folgende Funktion:
#include <curses.h> wrefresh(WINDOW *win);
Falls Sie überprüfen wollen, ob sich auf dem Fenster etwas verändert hat, können Sie dies mit der Funktion is_wintouched() abfragen.
#include <curses.h> int is_wintouched(WINDOW *win);
Ein kurzer Codeausschnitt, der dies demonstrieren soll:
// wurde Fenster verändert?
if(is_wintouched(fenster1))
// dann zeichne neu
wrefresh(fenster1);
else {
// tu so, als ob das Fenster verändert wurde
touchwin(fenster1);
// ... und zeichne dann neu
wrefresh(fenster1);
}
Wollen Sie einzelne Zeichen von einem Fenster in das andere Fenster kopieren, dann steht Ihnen folgende Funktionen zur Verfügung:
#include <curses.h> 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 folgt wieder ein für sich selbst sprechendes Programm, das Ihnen die meisten Fensterroutinen in der Praxis demonstrieren soll. Die Anwendung hält nach jedem Beispiel an, die Sie aber mit einem Tastendruck weiter ausführen können.
/* cur12.c */ #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 static void show_all_pairs(void) { int farbe1, farbe2, i=1, c; mvprintw(1,1,"Darstellung aller Farbpaare: \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 static 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(void) { WINDOW *fenster1,*fenster2; int y,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); // Wo ist das Fenster 2 genau? getbegyx(fenster2,y,x); // stdscr neuzeichnen touchwin(stdscr); refresh(); // Fenster 3 Zeilen tiefer und 20 Spalten nach links mvwin(fenster2,y+3,x-20); // Fenster 1 wurde nicht verändert ... // ... aber wir wollen trotzdem neu zeichnen ... touchwin(fenster1); wrefresh(fenster1); wrefresh(fenster2); wgetch(fenster2); mvwprintw(fenster1,5,5," Wir löschen Fenster 2 mit delwin() "); wrefresh(fenster1); wgetch(fenster1); // Fenster 2 löschen delwin(fenster2); 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; }
Mit ncurses ist es auch möglich, die Maus mit einzubeziehen. Gemeint sind damit allerdings jetzt hier nicht die Funktionen der Bibliothek gpm. Der Vorteil der Mausroutinen von ncurses ist, dass diese sowohl im Textmodus als auch im XTerm laufen.
|
Hinweis Zur Mausprogrammierung mit der gpm-Library finden Sie etwas auf der Buch-CD. |
Folgende Struktur wurde für die Mausprogrammierung mit ncurses definiert:
typedef struct {
short ID; // ID, falls mehrere Mäuse angeschlossen sind
int x,y,z; // Koordinaten, z nicht benötigt
mmask_t bstate; // Bitmaske für Mausknöpfe
} MEVENT;
Der Datentyp mmask_t ist ein primitiver Datentyp, der meistens als unsigned long dargestellt wird.
Damit ncurses überhaupt eine Mauseingabe zur Kenntnis nimmt, muss die Funktion mousemask() aufgerufen werden.
#include <curses.h> mmask_t mousemask(mmask_t neuemaske, mmask_t *altemaske);
Mit dem Parameter neuemaske geben Sie an, welche Mausereignisse bearbeitet werden sollen. Folgende Mausereignisse sind dabei in ncurses definiert:
#define BUTTON1_RELEASED 000000000001L #define BUTTON1_PRESSED 000000000002L #define BUTTON1_CLICKED 000000000004L #define BUTTON1_DOUBLE_CLICKED 000000000010L #define BUTTON1_TRIPLE_CLICKED 000000000020L #define BUTTON1_RESERVED_EVENT 000000000040L #define BUTTON2_RELEASED 000000000100L #define BUTTON2_PRESSED 000000000200L #define BUTTON2_CLICKED 000000000400L #define BUTTON2_DOUBLE_CLICKED 000000001000L #define BUTTON2_TRIPLE_CLICKED 000000002000L #define BUTTON2_RESERVED_EVENT 000000004000L #define BUTTON3_RELEASED 000000010000L #define BUTTON3_PRESSED 000000020000L #define BUTTON3_CLICKED 000000040000L #define BUTTON3_DOUBLE_CLICKED 000000100000L #define BUTTON3_TRIPLE_CLICKED 000000200000L #define BUTTON3_RESERVED_EVENT 000000400000L #define BUTTON4_RELEASED 000001000000L #define BUTTON4_PRESSED 000002000000L #define BUTTON4_CLICKED 000004000000L #define BUTTON4_DOUBLE_CLICKED 000010000000L #define BUTTON4_TRIPLE_CLICKED 000020000000L #define BUTTON4_RESERVED_EVENT 000040000000L #define BUTTON_CTRL 000100000000L #define BUTTON_SHIFT 000200000000L #define BUTTON_ALT 000400000000L #define ALL_MOUSE_EVENTS #define REPORT_MOUSE_POSITION
Wollen Sie jetzt z. B. überprüfen, ob die linke Maustaste gedrückt wurde, müssen Sie folgende Maske einrichten:
int maske = mousemask(BUTTON1_PRESSED, NULL);
Das Mausereignis können Sie mit wgetch() »einlesen«:
chtype button; button = wgetch(stdscr);
Wurde eine Mausaktivität (z. B. eine Maustaste wurde betätigt) registriert, so gibt wgetch() die symbolische Konstante KEY_MOUSE zurück:
if(button == KEY_MOUSE) {
//Mausaktivitäten
}
Welche Aktivität das jetzt genau war, lässt sich mit der folgenden Funktion herausfinden:
#include <curses.h> int getmouse(MEVENT *event);
Ein Codeausschnitt dazu sieht so aus:
MEVENT event;
...
if(getmouse(&event) == OK) {
// Konnte Mausereignis lesen
}
Der Rückgabewert der Funktion getmouse() lautet OK bei erfolgreichem Lesen, ansonsten bei einem Fehler ERR.
Jetzt, da mit der Funktion getmouse() die Strukturvariablen von MEVENT mit den entsprechenden Werten »belegt« wurden, können Sie diese wie folgt auswerten:
// y-Position des Mausereignisses y-Koordinate = event.y; // x-Position des Mausereignisses x-Koordinate = event.x; // (eventuell) Mausknopf, wenn betätigt bitmaske = event.bstate; // Maus-ID, falls mehrere "Mäuse" vorhanden ID = event.id;
Wollen Sie z. B. auf Doppelklick testen, müssen Sie eigentlich nur die Strukturvariable bstate wie folgt überprüfen:
If(event.bstate == BUTTON1_DOUBLE_CLICK) {
//der linke Mausbutton wurde doppelt geklickt
}
Um zu überprüfen, wo und ob im zulässigen Fenster die Mauskoordinate (y, x) liegt, benötigen Sie die Funktion:
#include <curses.h> bool wenclose(WINDOW *win, int y, int x);
Der Rückgabewert dieser Funktion lautet, falls das Mausereignis an einer gültigen Position im Fenster win auftrat, TRUE, ansonsten FALSE. Für x und y werden gewöhnlich die ermittelten Werte der Strukturvariablen x und y von MEVENT verwendet.
Ein kleines Programmbeispiel soll Ihnen die Verwendung der Maus mit ncurses demonstrieren. Sie klicken in einen Bereich des Fensters stdscr, und es werden die Werte zurückgegeben, an welcher Position genau Sie im Fenster den linken Mausbutton betätigt haben.
/* cur13.c */ #include <curses.h> #include <stdlib.h> int main (void) { MEVENT pos; int l_maus; chtype button; initscr (); noecho (); keypad (stdscr, TRUE); l_maus = mousemask (BUTTON1_PRESSED, NULL); while (1) { button = wgetch (stdscr); if (button == KEY_MOUSE) { if (getmouse (&pos) == OK) { wenclose (stdscr, pos.y, pos.x); mvwprintw (stdscr, 1, 0, "y = %2d x = %2d", pos.y, pos.x); } } wrefresh (stdscr); } endwin (); return 0; }
Dieses Beispiel soll jetzt noch durch die zusätzliche Überprüfung erweitert werden, an welcher Stelle im Fenster stdscr die Maustaste gedrückt wurde (y,x) und an welcher Stelle die Maustaste im Fenster wieder losgelassen wurde:
/* cur14.c */ #include <curses.h> #include <stdlib.h> int main (void) { MEVENT pos; int l_maus; chtype button; initscr (); noecho (); keypad (stdscr, TRUE); l_maus = mousemask ( BUTTON1_RELEASED | BUTTON1_PRESSED | BUTTON1_CLICKED, NULL); while (1) { button = wgetch (stdscr); clear (); if (button == KEY_MOUSE) { if (getmouse (&pos) == OK) { // linke Maustaste gedrückt ... if (pos.bstate == BUTTON1_PRESSED) { wenclose (stdscr, pos.y, pos.x); mvwprintw (stdscr, 1, 0, "linke Maustaste gedrückt bei y = %2d x = %2d", pos.y, pos.x); } // linke Maustaste losgelassen ... if (pos.bstate == BUTTON1_RELEASED) { // Reaktionszeit eine Tausendstelsekunde setzen mouseinterval (1); wenclose (stdscr, pos.y, pos.x); mvwprintw (stdscr, 2, 0, "linke Maustaste losgelassen y = %2d x = %2d", pos.y, pos.x); } } } wrefresh (stdscr); } endwin (); return 0; }
Wenn die Maustaste zu schnell oder zu langsam reagiert, können Sie (wie im Beispiel eben gesehen) die folgende Funktion zur Änderung benutzen:
#include <curses.h> int mouseinterval(int Tausendstelsekunde);
Zum Abschluss des Kapitels werden die Mausroutinen etwas praxisnäher eingesetzt. Sie erzeugen ein Fenster (WINDOW *fenster) und geben dieses auf dem Bildschirm aus. Sie können jetzt in jedem beliebigen Bereich im stdscr mit der linken Maus drücken, und das Fenster wird an diesem Punkt, falls möglich, versetzt. Als Ausgangspunkt dient die linke obere Ecke von stdscr. Weiterhin befindet sich an der linken oberen Ecke der Buchstabe 'S' und an der rechten oberen Ecke der Buchstabe 'M'. Mit 'S' für »Schließen« schließen Sie das Fenster und mit 'M' für »Maximieren« maximieren Sie es. Ein erneutes Klicken auf 'M' bewirkt wieder das Minimieren zur normalen Größe.
/* cur15.c */ #include <curses.h> #include <stdlib.h> #define MAXSIZE 1 #define MINSIZE 0 static int y_click, x_click; static int y_click2, x_click2; static int size = MINSIZE; static void where_clicked (WINDOW * win, WINDOW * win2, MEVENT pos) { // linke obere Ecke von win2 getbegyx (win2, y_click2, x_click2); mouseinterval (1); // wo in win wurde geklickt wenclose (win, pos.y, pos.x); y_click = pos.y; x_click = pos.x; // wurde auf die linke obere Ecke von win2 if (y_click == y_click2 && x_click == x_click2) { endwin (); exit (EXIT_FAILURE); } // ... oder wurde auf die rechte obere Ecke geklickt else if (y_click == y_click2 && x_click == x_click2 + 39 || x_click == x_click2 + 78) { touchwin (stdscr); refresh (); if (size == MINSIZE) { delwin (win2); size = MAXSIZE; } else if (size == MAXSIZE) { delwin (win2); size = MINSIZE; } } } /* Verschieben des Fensters an Position der globalen Variablen */ /* x_click und y_click, die zuvor mit where_clicked() ermittelt */ /* wurden */ static void move_win_to (WINDOW * win) { touchwin (stdscr); wrefresh (stdscr); mvwin (win, y_click + 1, x_click + 1); touchwin (win); wrefresh (win); } static WINDOW *create_new_window ( WINDOW * neues_fenster, int zeilen, int spalten, int hinterg, int vordergr, int begin_y, int begin_x ) { neues_fenster = newwin (zeilen, spalten, begin_y, begin_x); init_pair (1, hinterg, vordergr); wattrset (neues_fenster, COLOR_PAIR (1)); box (neues_fenster, ACS_VLINE, ACS_HLINE); return neues_fenster; } int main (void) { MEVENT pos; int l_maus; chtype button; WINDOW *fenster; initscr (); if (has_colors () == TRUE) start_color (); noecho (); keypad (stdscr, TRUE); fenster = create_new_window ( fenster, 10, 40, COLOR_RED, COLOR_BLUE, 5, 15); init_pair (2, COLOR_BLACK, COLOR_YELLOW); wattrset (fenster, COLOR_PAIR (2)); mvwaddch (fenster, 0, 0, 'S'); mvwaddch (fenster, 0, 39, 'M'); wattrset (fenster, COLOR_PAIR (0)); mvwprintw (fenster, 2, 10, "S=Fenster schliessen"); mvwprintw (fenster, 6, 10, "M=Fenster maximieren"); wrefresh (fenster); l_maus = mousemask (BUTTON1_RELEASED | BUTTON1_PRESSED, NULL); while (1) { button = wgetch (stdscr); if (button == KEY_MOUSE) { if (getmouse (&pos) == OK) { where_clicked (stdscr, fenster, pos); // move_win_to(fenster); if (size == MAXSIZE) { fenster = create_new_window (fenster, 24, 79, COLOR_RED, COLOR_BLUE, 0, 0); wattrset (fenster, COLOR_PAIR (2)); mvwaddch (fenster, 0, 0, 'S'); mvwaddch (fenster, 0, 78, 'M'); wattrset (fenster, COLOR_PAIR (0)); mvwprintw (fenster, 10, 30, "S=Fenster schliessen"); mvwprintw (fenster, 14, 30, "M=Fenster minimieren"); wrefresh (fenster); } else if (size == MINSIZE) { fenster = create_new_window (fenster, 10, 40, COLOR_RED, COLOR_BLUE, 5, 15); init_pair (2, COLOR_BLACK, COLOR_YELLOW); wattrset (fenster, COLOR_PAIR (2)); mvwaddch (fenster, 0, 0, 'S'); mvwaddch (fenster, 0, 39, 'M'); wattrset (fenster, COLOR_PAIR (0)); mvwprintw (fenster, 2, 10, "S=Fenster schliessen"); mvwprintw (fenster, 6, 10, "M=Fenster maximieren"); wrefresh (fenster); move_win_to (fenster); } } } } endwin (); return 0; }
So sieht‘s aus:
|
Abbildung 13.3 Eine einfache Dialogbox für die Konsole |
|
Hinweis In diesem Listing wird ebenfalls davon ausgegangen, dass Sie eine gewöhnliche 80 x 24 cm große Konsole (z. B. VT100) verwenden. Andernfalls kann die Anwendung nicht richtig laufen (es sei denn, Sie passen die Breite der Konsole dem Listing an). |
Mit diesem Grundwissen können Sie jetzt eine passable Benutzeroberfläche für die Konsole bauen. Zwei weitere Funktionen zur Mausprogrammierung mit ncurses, die es noch gibt, hier aber nicht durchgenommen wurden, wären:
int ungetmouse(MEVENT *event); bool wmouse_trafo(WINDOW *win, int *Py, int *Px);
Für nähere Informationen lesen Sie bitte die Manual Page (man mouse).
|
Hinweis Ursprünglich hätte ich hier gerne noch ein etwas umfangreicheres Beispiel demonstriert. Es handelt sich dabei um ein Videoverwaltungsprogramm mit ncurses und den verketteten Listen. Da das Listing allein mehrere Seiten im Buch verschlungen hätte und ich Ihnen das nicht zumuten will, finden Sie das Beispiel auf der Buch-CD wieder. |
| << zurück |
|
||||||||||||
|
||||||||||||
|
||||||||||||
Copyright © Rheinwerk Verlag GmbH 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich
ausdrucken. Ansonsten unterliegt das Openbook denselben Bestimmungen,
wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist
urheberrechtlich geschützt.
Alle Rechte vorbehalten einschließlich der
Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und
Verarbeitung in elektronischen Systemen.