Ncurses: Druckversion
Ncurses ist eine C-Bibliothek für die Steuerung von Textterminals. Hauptzweck dieser Bibliothek ist die Erstellung von TUIs (Text User Interfaces). Typische Beispiele für Programme, deren Benutzeroberflächen die ncurses-Bibliothek benutzen sind der Lynx-Browser (alternativ zur S-Lang-Bibliothek), der GNU Midnight Commander (alternativ zur S-Lang-Bibliothek), das Linux-Kernel-Konfigurationsprogramm in der ncurses-Variante oder das ncurses-Frontend des YaST-Installations- und -Konfigurationsprogramms bei der SuSE-Linux-Distribution.
-
alsamixer (Audio-Mischer für ALSA)
-
Lynx (Webbrowser)
-
Mutt (E-Mail-Programm)
-
Midnight Commander (Dateimanager, oben rechts)
Ncurses ist weitgehend kompatibel mit den SVR4-curses. Ncurses ist für diverse Unix-Plattformen erhältlich und steht unter der MIT-Lizenz.
Neben ncurses sind auch andere curses-Weiterentwicklungen erhältlich. Als Beispiel sei PDCurses genannt, welches für MS DOS, MS Windows, OS/2 und X11-Systeme verfügbar ist. Dieses Buch bezieht sich jedoch explizit auf ncurses, d.h. die erläuterten Grundlagen und Beispiele können, müssen jedoch nicht auf andere Curses-Bibliotheken gleichermaßen zutreffen.
Der Code wird mit einem beliebigen Texteditor als .c Datei gespeichert und dann mit:
gcc -lncurses <dateiname>.c -o <programmname>
compiliert. Vorher müssen natürlich auf dem Computer gcc und die ncurses Biblioteken installiert werden. Unter Debian GNU/Linux geht das z.B. sehr einfach mit
apt-get install build-essential libncurses5-dev
Dann kann man loslegen.
Installation
[Bearbeiten]ncurses ist zumindest unter Linux (fast) immer Bestandteil der Distributionen und kann, wenn nicht bereits bei der initialen Linuxinstallation geschehen, nachträglich einfach vom Installationsmedium installiert werden. Eine ncurses-Downloadmöglichkeit wird im Kapitel Weblinks genannt.
Die Headerdateien
[Bearbeiten]Die ncurses-Standard-Headerdateien sind
curses.h
oder
ncurses.h
ncurses.h
ist meist nur ein symbolischer Link auf curses.h
Des Weiteren enthält ncurses für Spezialeinsatzfälle noch weitere Header-Dateien:
- Panels:
panel.h
- Menüs:
menu.h
- Formulare:
form.h
Die Bibliotheken
[Bearbeiten]Die ncurses-Standardfunktionen sind in der Bibliothek
libncurses.xx
versammelt, wobei xx
für so
(shared object) oder a
(statische Programmbibliothek) steht.
Äquivalent zu den Header-Dateien gibt es noch zusätzliche ncurses-Bibliotheken:
- Panels:
libpanel.xx
- Menüs:
libmenu.xx
- Formulare:
libform.xx
Die ncurses-man-Pages
[Bearbeiten]Mit ncurses werden umfangreiche und ausführliche Manual-Seiten mitgeliefert.
Der Aufruf der ncurses-Übersichtsseite erfolgt mittels
man ncurses
oder
info ncurses
Auch die Beschreibungen der einzelnen ncurses-Funktionen lassen sich so abfragen, z.B.
man mvaddstr
oder
man 3ncurses mvaddstr
Fenster
[Bearbeiten]Ein Fenster (Window) repräsentiert einen rechteckigen Bildschirmausschnitt. In einer WINDOW
-Datenstruktur werden die notwendigen Attribute und Daten des entsprechenden Bildschirmausschnittes gespeichert. In curses.h
findet sich dieses Konstrukt unter struct _win_st
. WINDOW
ist nur ein Synonym für _win_st
(typedef struct _win_st WINDOW
).
Bildschirme
[Bearbeiten]Bildschirme (Screens) sind Zeiger auf eine WINDOW-Datenstruktur.
ncurses kennt beim Start zwei Screens:
- Standardbildschirm (standard screen):
stdscr
- Aktueller Bildschirm (current screen):
curscr
Der stdscr
ist das Hauptfenster, welches vom Programmierer mittels ncurses-Anweisungen beeinflusst werden kann. Der curscr
repräsentiert das, was momentan am Bildschirm angezeigt wird. Bei einem Refresh werden in diesen Screen die vorgenommenen Änderungen eingebracht und die Darstellung am physikalischen Bildschirm aktualisiert.
ncurses und I/O-Befehle von C
[Bearbeiten]Befindet sich ein Programm im ncurses-Modus, so dürfen (oder sollen, können) die C-Standardfunktionen nicht zur Ein- und Ausgabe (z.B. printf, scanf) verwendet werden. Zu diesem Zweck stellt ncurses eigene Funktionen zur Verfügung.
Termcap und Terminfo
[Bearbeiten]termcap steht für Terminal Capabilities und ist eine Datei, in der die Fähigkeiten (Zeilen-, Spaltenanzahl, ...) zahlreicher Terminals hinterlegt sind.
terminfo leistet prinzipiell das gleiche wie termcap. Allerdings liegen in der terminfo-Datenbank die Terminal-Fähigkeitsbeschreibungen nicht in einer einzigen Gesamtdatei vor, sondern als separate Dateien alphabetisch geordnet in Unterverzeichnissen.
Bei der ncurses-Initialisierung wird mittels der Environmentvariablen TERM
die termcap/terminfo ausgewertet. Daraus kann ncurses die relevanten Daten des verwendeten Terminals ermitteln (z.B. Anzahl der Zeilen und Spalten).
Ncurses initialisieren und beenden
[Bearbeiten]Die ncurses-Initialisierung geschieht mittels der Funktion
WINDOW *initscr (void);
initscr
wird in den meisten Fällen die erste ncurses-Funktion sein, die in einem Programm aufgerufen wird.
Beendet wird der ncurses-Modus mit der Funktion
int endwin (void);
Ein ncurses-Programm soll unbedingt ordentlich mit der endwin
-Funktion beendet werden.
Der ncurses-Modus kann durch endwin
auch zeitweilig unterbrochen werden. Die Rückkehr zum ncurses-Modus erfolgt durch eine Refresh-Anweisung.
Mit der Funktion bool isendwin()
kann abgefragt werden, ob der ncurses-Modus noch aktiv ist.
bool
ist übrigens ein Boolean-Datentyp den ncurses mitbringt. Zulässige Werte sind TRUE
(= 1) und FALSE
(= 0). Dass C++-Compiler oder andere Bibliotheken ebenfalls einen bool
-Datentyp kennen, wird in der ncurses-Headerdatei berücksichtigt.
Das ncurses-Hauptkoordinatensystem
[Bearbeiten]
Zwecks Abfrage von Fenster- und Cursorkoordinaten stehen folgende Makros zur Verfügung:
getyx(win, y, x); // Koordinaten der aktuellen Cursorposition getparyx(win, y, x); // Koordinatenursprung von win bezogen auf das // übergeordnete Fenster getbegyx(win, y, x); // Koordinatenursprung getmaxyx(win, y, x); // Fenstergröße (Anzahl der Zeilen und Spalten)
Wobei win
ein Zeiger auf das abzufragende WINDOW
ist und die Koordinatenwerte als Integerwerte in y
(Zeile) und x
(Spalte) geliefert werden.
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> //noetig fuer atexit() void quit() { endwin(); } int main(void) { int x, y; initscr(); atexit(quit); curs_set(0); mvprintw(3, 5, "LINES: %d", LINES); mvprintw(4, 5, "COLS: %d", COLS); getyx(stdscr, y, x); mvprintw(5, 5, "Momentane Cursorposition: [%d, %d]", y, x); getbegyx(stdscr, y, x); mvprintw(6, 5, "Koordinatenursprung: [%d, %d]", y, x); getmaxyx(stdscr, y, x); mvprintw(7, 5, "Fenstergröße: [%d, %d]", y, x); mvaddstr(11, 2, "Taste drücken -> Ende"); refresh(); getch(); return(0); }
Die Bedeutung der einzelnen Bildschirmausgabefunktionen wird später näher beschrieben. Das Compilieren und Linken des Beispieles kann mit folgendem Kommando geschehen
gcc -o bsp bsp.c -lncurses
Voraussetzungen für das erfolgreiche Compilieren/Linken dieses Beispiels in der vorgeschlagenen Art und Weise:
- Das Beispiel wurde unter dem Dateinamen
bsp.c
abgespeichert und der Compileraufruf erfolgt aus dem selben Verzeichnis in dembsp.c
gespeichert wurde. - Sie verwenden das C-Frontend der GNU Compiler Collection (GCC). Diese GCC muss für das Compilieren/Linken des Beispiels auf ihrem System installiert sein. Die Verwendung eines anderen Compilers wird einen etwas anderen Compileraufruf erfordern.
- Sie geben das Kommando direkt nach dem Prompt in ein Terminal ein. Für andere Arten der Programmerstellung, z.B. via IDE, sei hier nur der allgemeine Hinweis "die Einbindung der
ncurses
-Bibliothek nicht vergessen" gegeben.
Das ausführbare Programm sollte nach erfolgreichem Compilerlauf unter dem Dateinamen bsp
vorhanden sein. Der Programmstart kann mit
./bsp
direkt aus dem Speicherverzeichnis des Beispielprogramms erfolgen. Das Ergebnis sollte folgendem Screenshot ähneln.
Die konkret angezeigten Zahlenwerte hängen natürlich vom verwendeten Terminal ab.
Cursor
[Bearbeiten]Zwecks Positionierung des Cursors steht die Funktion
int move(int y, int x);
zur Verfügung. Der Cursor bestimmt, an welcher Position die Textausgabe oder ein Echo erfolgt. ncurses-Text-I/O-Funktionen existieren meist zusätzlich als Variante mit einem mv
-Präfix, sodass Cursorpositionierung und Daten-I/O in einem Rutsch erledigt werden können und nicht jeweils zwei Funktionen nacheinander angeschrieben werden müssen.
Die Cursoranzeige lässt sich mit der Funktion
int curs_set(int visibility);
modifizieren. Für visibility
sind folgende Werte möglich:
- 0 ... unsichtbar
- 1 ... sichtbar
- 2 ... "besonders" sichtbar.
Textausgabe
[Bearbeiten]Die ncurses-Bibliothek kennt, ihrem Einsatzzweck entsprechend, eine Vielzahl von Textausgabefunktionen.
Hinzufügen von Einzelzeichen
[Bearbeiten]int addch(const chtype ch); int mvaddch(int y, int x, const chtype ch); int echochar(const chtype ch);
echochar
entspricht einem addch
mit nachfolgendem refresh
.
Einfügen eines Zeichens
[Bearbeiten]int insch(chtype ch); int mvinsch(int y, int x, chtype ch);
Beispiel: Unterschied zwischen addch() und insch()
[Bearbeiten]#include <curses.h> #include <stdlib.h> //noetig fuer atexit() void quit() { endwin(); } int main(void) { initscr(); atexit(quit); curs_set(0); mvaddstr(3, 2, "Der Unterschied zwischen addch() und insch():"); mvaddstr(5, 5, "ADDCH: Hallo, Welt"); mvaddch(5, 13, 'A'); mvaddstr(6, 5, "INSCH: Hallo, Welt"); mvinsch(6, 13, 'A'); refresh(); getch(); return(0); }
Hinzufügen einer Zeichenkette
[Bearbeiten]int addstr(const char *str); int addnstr(const char *str, int n); int mvaddstr(int y, int x, const char *str); int mvaddnstr(int y, int x, const char *str, int n);
Einfügen einer Zeichenkette
[Bearbeiten]int insstr(const char *str); int insnstr(const char *str, int n); int mvinsstr(int y, int x, const char *str); int mvinsnstr(int y, int x, const char *str, int n);
Formatierte Ausgabe
[Bearbeiten]int printw(const char *fmt, ...); int mvprintw(int y, int x, const char *fmt, ...); int vwprintw(WINDOW *win, const char *fmt, va_list var glist);
Die Parameter, insbesondere fmt
, von printw
entsprechen der printf
-Funktion in stdio.h
. Nachfolgend sind auszugsweise einige Konvertierungszeichen zwecks Verwendung in fmt
gegeben
%d, %i | vorzeichenbehaftete Ganzzahl (int) |
%o | vorzeichenlose Ganzahl im Oktalformat |
%u | vorzeichenlose Ganzzahl (unsigned int) |
%x | vorzeichenlose Ganzahl im Hexadezimalformat |
%f, %F | Gleitkommazahl (double) |
%e, %E | Gleitkommazahl (double) in Exponentialdarstellung |
%a, %A | Gleitkommazahl (double) in Hexadezimaldarstellung |
%s | Zeichenkette (const char *) |
%c | Ein Zeichen (char) |
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> //noetig fuer atexit() void quit() { endwin(); } int main(void) { const int i = 23456; const double f = -12345e-3; initscr(); atexit(quit); curs_set(0); mvprintw(3, 2, "Eine Ganzzahl in Oktal- und Hexadezimaldarstellung: %o | %x\n", i, i); mvprintw(4, 2, "Eine Ganzzahl mit führenden Nullen: %010d\n", i); mvprintw(5, 2, "Eine Gleitkommazahl: %8.3f\n", f); mvprintw(6, 2, "Eine Gleitkommazahl: %8.3e\n", f); mvprintw(7, 2, "Eine Gleitkommazahl in Hexadezimaldarstellung: %a\n", f); refresh(); getch(); return(0); }
Texteingabe
[Bearbeiten]Eine Benutzeroberfläche ohne die Möglichkeit von Benutzereingaben ist in den meisten Fällen relativ nutzlos. Die ncurses-Bibliothek stellt eine Reihe von Funktionen für die Dateneingabe mittels Tastatur zur Verfügung.
Eingabe eines Zeichens
[Bearbeiten]int getch(void); int mvgetch(int y, int x); int ungetch(int ch); int wgetch(WINDOW *win);
getch
entspricht in etwa der getchar
-Funktion aus stdio.h
. ungetch
schreibt das Zeichen ch
zurück in die Eingabe-Queue. wgetch
ist eine Funktion für die Zeicheneingabe in eigens festgegelegten Fenstern. Die Programmierung von Fenstern wird aber erst in einem der folgenden Kapitel näher beschrieben.
Die Interpretation eines Return-Tastendrucks ist nicht einheitlich geregelt. Ncurses bietet zu diesem Zwecke zwei unterschiedliche Funktionen.
int nl(void); int nonl(void);
Bei der Verwendung von nl()
wird ein Return-Tastendruck (Zeilenendezeichen) als 0xA (10dec, LF, Line Feed) interpretiert. Bei der Verwendung von nonl()
entspricht ein Return-Tastendruck nur einem 0xD (13dec, CR, Carriage Return).
Eingabe einer Zeichenkette
[Bearbeiten]getstr(char *str); getnstr(char *str, int n); mvgetstr(int y, int x, char *str); mvgetnstr(int y, int x, char *str, int n);
Formatierte Eingabe
[Bearbeiten]int scanw(char *fmt, ...); int mvscanw(int y, int x, char *fmt, ...); int vwscanw(WINDOW *win, char *fmt, va_list varglist);
scanw
ist vergleichbar mit dem konventionellen scanf
.
Löschaktionen
[Bearbeiten]Ab und zu wird auch eine "tabula rasa"-Aktion fällig.
int clear(void); int clrtobot(void); int clrtoeol(void);
clear
löscht den gesamten Standardscreen. clrtobot
löscht die Inhalte von der aktuellen Cursorposition bis zum Ende des Screens. clrtoeol
löscht die Inhalte von der aktuellen Cursorposition bis zum Zeilenende.
Die Funktion
int deleteln(void);
löscht die gesamte aktuelle Zeile. Alle darauffolgenden Zeilen werden um eine Zeile nach oben verschoben. Andererseits fügt die Funktion
int insertln(void);
eine Leerzeile an der aktuellen Cursorposition ein. Alle folgenden Zeilen werden um eine Zeile nach unten verschoben.
Refresh
[Bearbeiten]Damit die Änderungen im stdscr
in den curscr
übernommen werden und somit der Bildschirm aktualisiert wird, ist folgende Anweisung vorhanden:
int refresh(void);
Scrolling
[Bearbeiten]int scroll(WINDOW *win); int scrl(int n);
scroll
verschiebt den Fensterinhalt um eine Zeile nach oben. scrl
verschiebt den Fensterinhalt von stdscr
um n
Zeilen nach oben.
Damit Scrolling funktioniert, muss vorab folgende Funktion aufgerufen werden.
int scrollok(WINDOW *win, bool bf);
Der Parameter bf
muss für die Aktivierung der Scrollfähigkeit natürlich auf TRUE
gesetzt werden.
Echo ein-/ausschalten
[Bearbeiten]Die Anzeige der Eingabedaten (das Echo) kann mittels der Funktion
noecho()
unterdrückt werden.
echo()
schaltet diese Anzeige wieder ein. Dies ist das Standardverhalten von ncurses.
Pieps und Blitz
[Bearbeiten]Manchmal kann auch ein kurzes Warnsignal an den Benutzer sinnvoll sein. Ncurses bietet zu diesem Zweck zwei standardmäßig vorhandene Funktionen:
int beep(void); int flash(void);
beep()
soll einen kurzen akustischen Ton und flash()
einen kurzen optischen "Flash" erzeugen. Das Ganze ist aber stark abhängig von den Fähigkeiten und Einstellungen des verwendeten Terminals. Besitzt das verwendete Terminal weder Audio- noch Flashfähigkeiten, dann erfolgt weder eine akustische noch eine visuelle Warnung. Teilweise können diese Signale vom Benutzer auch deaktiviert werden, so z.B. bei der KDE-Konsole. Der Gebrauch dieser Funktionen ist deshalb nur von eingeschränktem Nutzen.
gcc -lcurses
[Bearbeiten]Falls ncurses nicht funktioniert, dann sollte man die Compileroption -lcurses versuchen. Beispiel gcc main.c -o demo -lcurses
Damit ncurses-Programme in ihrer ganzen Farbenpracht erstrahlen können, muss im Programmcode die Funktion
int start_color(void);
initial aufgerufen werden.
Beispiel
[Bearbeiten]#include <curses.h>
#include <stdlib.h>
void quit(void)
{
endwin();
}
int main(void)
{
initscr();
atexit(quit);
start_color();
clear();
mvaddstr(5, 5, "Hallo");
mvaddstr(6, 10, "Welt!");
mvaddstr(15, 1, "Programm beenden durch Drücken einer Taste");
refresh();
getch();
return(0);
}
Das Rechteck rechts-unten auf diesem und den folgenden Screenshots stellt übrigens den Cursor dar. Die Anzeige des Cursors kann mit der curs_set
-Funktion ein-/ausgeschaltet werden.
Farben wählen
[Bearbeiten]int init_pair(short pair, short f, short b);
Parameter:
pair
: Paarnummer;1 <= pair < COLOR_PAIRS
f, b
: foreground-color, background-color;1 <= (f bzw. b) < COLOR
Diese Funktion ist nur dann sinnvoll einsetzbar, wenn das Terminal Farben unterstützt, was aber auch häufig der Fall ist. Zwecks Abfrage der Farbfähigkeit gibt es die Funktion
bool has_colors(void);
Basisfarben
[Bearbeiten]Nach der Initalisierung mittels start_color
sind bei farbfähigen Terminals unmittelbar die acht ncurses-Basisfarben verwendbar:
COLOR_BLACK | = 0 | ♦ |
COLOR_RED | = 1 | ♦ |
COLOR_GREEN | = 2 | ♦ |
COLOR_YELLOW | = 3 | ♦ |
COLOR_BLUE | = 4 | ♦ |
COLOR_MAGENTA | = 5 | ♦ |
COLOR_CYAN | = 6 | ♦ |
COLOR_WHITE | = 7 | ♦ |
Textvorder- und -hintergrundfarbe
[Bearbeiten]int color_set(short color_pair_number, void* opts);
Farben werden immer paarweise (Vorder-, Hintergrundfarbe) gesetzt (init_pair
). Der Parameter opts
ist ein Null-Pointer (0).
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> void quit(void) { endwin(); } int main(void) { initscr(); atexit(quit); start_color(); clear(); init_pair(1, COLOR_GREEN, COLOR_RED); color_set(1, 0); mvaddstr(5, 5, "Hallo"); mvaddstr(6, 10, "Welt!"); mvaddstr(15, 1, "Programm beenden durch Drücken einer Taste"); refresh(); getch(); return(0); }
Fensterhintergrund
[Bearbeiten]int bkgd(chtype ch);
Beispiel
[Bearbeiten]#include <curses.h>
#include <stdlib.h>
void quit(void)
{
endwin();
}
int main(void)
{
initscr();
atexit(quit);
start_color();
clear();
init_pair(1, COLOR_GREEN, COLOR_RED);
bkgd(COLOR_PAIR(1));
mvaddstr(5, 5, "Hallo");
mvaddstr(6, 10, "Welt!");
mvaddstr(15, 1, "Programm beenden durch Drücken einer Taste");
refresh();
getch();
return(0);
}
Zusätzliche Textattribute
[Bearbeiten]Zusätzliche Textattribute lassen sich mit den Funktionen
int attrset(int attrs); // setzt Attribute für nachfolgende Texte int attron(int attrs); // schaltet zusätzliche Attribute für nachfolgende Texte ein int attroff(int attrs); // schaltet die angegebenen Attribute wieder aus int standend(void); // attrset(0) int standout(void); // attrset(A_STANDOUT)
einstellen. Einzelattribute lassen sich mittels der OR-Bitoperation ( | ) verknüpfen. Als Attribute stehen zur Verfügung:
A_NORMAL | normal |
A_STANDOUT | Highlight-Modus |
A_UNDERLINE | unterstrichen |
A_REVERSE | revertiert |
A_BLINK | blinkend |
A_DIM | gedimmt |
A_BOLD | fett |
A_PROTECT | geschützt |
A_INVIS | unsichtbar |
A_ALTCHARSET | alternatives Character-Set |
Die genauen Auswirkungen dieser Attribute sind teilweise abhängig von den Fähigkeiten des eingesetzten Terminals.
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> void quit(void) { endwin(); } int main(void) { initscr(); atexit(quit); start_color(); clear(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_GREEN, COLOR_BLUE); bkgd(COLOR_PAIR(1)); attrset(A_UNDERLINE); mvaddstr(5, 5, „Hallo“); attrset(A_BOLD); mvaddstr(6, 10, „Welt!“); attrset(A_DIM | COLOR_PAIR(2)); mvaddstr(15, 1, "Programm beenden durch Drücken einer Taste"); refresh(); getch(); return(0); }
KDE-Konsole (Farbschema: Konsole-Standard) | |
KDE-Konsole (Farbschema: XTerm-Farben) | |
rxvt, aterm, xterm |
Farben ändern
[Bearbeiten]int init_color(short color, short r, short g, short b);
Parameter:
color
: Farb-Nummer bzw. -Name (COLOR_BLACK, etc.) der Basisfarbe, die geändert werden sollr, g, b
: ... RGB;0 <= (r, g bzw. b) <= 1000
Diese Funktion ist nur dann sinnvoll einsetzbar, wenn das Terminal Farbänderungen unterstützt, was nicht immer der Fall ist (Software Terminals können für diesen Zweck z.b. in den Modus "xterm-256color" geschalten werden). Je nach Terminal wird nur ein kleinerer Wertebereich unterstützt, z.B.: 0 <= (r, g bzw. b) <= 999
. Zwecks Abfrage der Fähigkeit zur Farbänderung gibt es die Funktion
bool can_change_color(void);
Da die Funktion nur sehr selten sinnvoll angewendet werden kann, wird hier auf ein Beispiel verzichtet.
Damit Spezialtasten (z.B. Pfeiltasten, Funktionstasten, Backspace-Taste) korrekt angesprochen werden, müssen mittels
int keypad(WINDOW *win, bool bf);
deren ncurses-Escapesequenzen aktiviert werden.
Nachfolgend die Bezeichnung einiger häufig benötigter Spezialtasten. Zwecks vollständiger Auflistung wird auf die ncurses-Header-Datei curses.h
hingewiesen:
KEY_DOWN | |
KEY_UP | |
KEY_LEFT | |
KEY_RIGHT | |
KEY_BACKSPACE | |
KEY_F(1), ... | Funktionstaste F1, ... |
KEY_END | |
KEY_PRINT |
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> void quit(void) { endwin(); } int main(void) { initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, TRUE); mvaddstr(5, 5, "Hallo"); mvaddstr(6, 10, "Welt!"); mvaddstr(10, 1, "Programm beenden durch Drücken der Taste F1"); refresh(); while(getch() != KEY_F(1)) { } return(0); }
Damit dieses Beispiel ordnungsgemäß funktioniert, muss die Zeilenpufferung und teilweise Einzelzeichenbearbeitung für das Textterminal ausgeschaltet sein. Sicherheitshalber sollte dieser "cbreak"-Modus explizit aktiviert werden, denn es ist nicht garantiert, dass sich das Terminal automatisch in diesem Modus befindet. Testweise kann in diesem Beispiel die cbreak
-Funktion durch die nocbreak
-Funktion ersetzt werden. Das Programm lässt sich dann nicht mehr durch Drücken der F1
-Funktionstaste beenden. nocbreak()
versetzt das Terminal wieder in den sogenannten "cooked"-Modus. Zusätzlich kann das Terminal auch noch mittel raw()
in den "raw"-Modus versetzt werden. Dieser unterscheidet sich vom "cbreak"-Modus dadurch, dass die Einzelzeichenbearbeitung komplett ausgeschaltet wird, dem Prozess werden alle Zeichen unverarbeitet zur Verfügung gestellt. Im "cbreak"-Modus ließe sich das Programm notfalls auch noch durch die Tastenkombination CRTL-C
beenden. Im "raw"-Modus würde dieses Zeichen keinen Interrupt mehr auslösen, sondern wie jedes normale Zeichen an das Programm weitergeleitet werden.
Bisher wurde bei den Programmen nur der Standardscreen stdscr
als Fenster verwendet. Mit ncurses können aber auch eigene Fenster erzeugt und manipuliert werden. Die Funktionen für Fenster sind sehr ähnlich wie die bisher verwendeten. Allerdings sind die speziellen Fenster-Befehle durch den zusätzlichen Buchstaben w
markiert, z.B.:
int wrefresh(WINDOW *win); int wscanw(WINDOW *win, char *fmt, ...); int mvwaddstr(WINDOW *win, int y, int x, const char *str);
Tatsächlich ist es sogar so, dass die bisher verwendeten Standardscreen-Funktionen nur als Makros definiert sind, z.B.:
#define addch(ch) waddch(stdscr,ch) #define attron(at) wattron(stdscr,at) #define bkgd(ch) wbkgd(stdscr,ch) #define clear() wclear(stdscr)
Zum Erzeugen von Fenstern gibt es mehrere Möglichkeiten:
- Neue Fenster erzeugen:
newwin
- Abgeleitete Fenster erzeugen:
subwin, derwin
- Fenster duplizieren:
dupwin
Neue Fenster
[Bearbeiten]WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x);
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> WINDOW *win; void quit(void) { delwin(win); endwin(); } int main(void) { initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, 1); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_WHITE); win = newwin(5, 20, 10, 10); bkgd(COLOR_PAIR(1)); wbkgd(win, COLOR_PAIR(2)); mvaddstr(5,5, "Hallo stdscr"); mvwaddstr(win, 3, 3, "Hallo win"); mvwaddstr(win, 7, 3, "Diese Zeichenkette wird nicht angezeigt!"); // da ausserhalb des win-Anzeigebereichs refresh(); wrefresh(win); while(getch() != KEY_F(1)) { } return(0); }
Abgeleitete Fenster
[Bearbeiten]Ein subwin
(untergeordnetes Fenster) erbt Eigenschaften vom übergeordneten Fenster.
WINDOW *subwin(WINDOW *orig, int nlines, int ncols, int begin_y, int begin_x);
Beispiel: Aufzeigen des Unterschieds von newwin und subwin
[Bearbeiten]#include <curses.h> #include <stdlib.h> WINDOW *win1, *win2; void quit(void) { delwin(win1); delwin(win2); endwin(); } int main(void) { initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, 1); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); win1 = newwin(5, 20, 10, 10); win2 = subwin(stdscr, 5, 20, 10, 35); bkgd(COLOR_PAIR(1)); mvaddstr(5,5, "Hallo stdscr"); mvwaddstr(win1, 3, 3, "Hallo newwin"); mvwaddstr(win2, 3, 3, "Hallo subwin"); refresh(); wrefresh(win1); wrefresh(win2); while(getch() != KEY_F(1)) { } return(0); }
derwin
ist im Prinzip das selbe wie subwin
. Während die Position (begin_y, begin_x
) des Fensters bei der Funktion subwin
aber relativ zum Screen festgelegt wird, ist die Position bei derwin
relativ zum orig
-Fenster.
Fensterverzierungen
[Bearbeiten]Fenster können auch mit Rahmen oder Begrenzungslinien versehen werden. Diese Verzierungen werden mittels Einzelzeichen aufgebaut. Diese Zeichen können gewöhnliche Buchstaben oder Zahlen sein. Schöner wird das Ganze aber wenn spezielle Zeichen verwendet werden. ncurses kennt "form characters" (ACS, Alternative Character Set), die sich für dieses Aufgabengebiet anbieten. Zu beachten ist, dass Rahmen und Linien wie normaler Text geschrieben werden. Aus diesem Grund können diese Rahmen durch unvorsichtig platzierten Text überschrieben werden. Das bringt zwar keine funktionellen Nachteile, sieht aber nicht schön aus. Dies sollte bei der Verwendung von Rahmen und Linien beachtet werden.
Rahmen
[Bearbeiten]int border(chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, chtype bl, chtype br); int wborder(WINDOW *win, chtype ls, chtype rs, chtype ts, chtype bs, chtype tl, chtype tr, chtype bl, chtype br); int box(WINDOW *win, chtype verch, chtype horch);
Erklärung der Parameterbezeichnungen:
- ver ... vertikal
- hor ... horizontal
- l ... left
- r ... right
- b ... bottom
- t ... top
- s ... side
Z.B. bedeuten
ls
... left side, Kante linkstr
... top right, Ecke oben-rechts
Wird 0 übergeben, so wird jeweils das in der Bibliothek festgelegte Standardzeichen verwendet.
Linien
[Bearbeiten]int hline(chtype ch, int n); int vline(chtype ch, int n); int whline(WINDOW *win, chtype ch, int n); int wvline(WINDOW *win, chtype ch, int n); int mvhline(int y, int x, chtype ch, int n); int mvvline(int y, int x, chtype ch, int n); int mvwhline(WINDOW *, int y, int x, chtype ch, int n); int mvwvline(WINDOW *, int y, int x, chtype ch, int n);
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> WINDOW *win; void quit(void) { delwin(win); endwin(); } int main(void) { initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, 1); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_WHITE); win = newwin(5, 20, 10, 10); bkgd(COLOR_PAIR(1)); wbkgd(win, COLOR_PAIR(2)); mvaddstr(5,5, "Hallo stdscr"); mvwaddstr(win, 3, 3, "Hallo win"); mvwaddstr(win, 7, 3, "Diese Zeichenkette wird nicht angezeigt!"); // da ausserhalb des win-Anzeigebereichs box(win, 0, 0); mvhline(7, 1, ACS_BULLET, 20); refresh(); wrefresh(win); while(getch() != KEY_F(1)) { } return(0); }
ACS (Liniengrafik, form characters)
[Bearbeiten]Obige ACS-Bilder wurden als Screenshoots dieses Programmes erstellt (KDE-Konsole, xterm)
#include <curses.h> #include <stdlib.h> void write_pages(void) { chtype acs_symbol[] = { ACS_ULCORNER, ACS_LLCORNER, ACS_URCORNER, ACS_LRCORNER, ACS_LTEE, ACS_RTEE, ACS_BTEE, ACS_TTEE, ACS_HLINE, ACS_VLINE, ACS_PLUS, ACS_S1, ACS_S9, ACS_DIAMOND, ACS_CKBOARD, ACS_DEGREE, ACS_PLMINUS, ACS_BULLET, ACS_LARROW, ACS_RARROW, ACS_DARROW, ACS_UARROW, ACS_BOARD, ACS_LANTERN, ACS_BLOCK, ACS_S3, ACS_S7, ACS_LEQUAL, ACS_GEQUAL, ACS_PI, ACS_NEQUAL, ACS_STERLING }; char acs_name[][20] = { "ACS_ULCORNER", "ACS_LLCORNER", "ACS_URCORNER", "ACS_LRCORNER", "ACS_LTEE", "ACS_RTEE", "ACS_BTEE", "ACS_TTEE", "ACS_HLINE", "ACS_VLINE", "ACS_PLUS", "ACS_S1", "ACS_S9", "ACS_DIAMOND", "ACS_CKBOARD", "ACS_DEGREE", "ACS_PLMINUS", "ACS_BULLET", "ACS_LARROW", "ACS_RARROW", "ACS_DARROW", "ACS_UARROW", "ACS_BOARD", "ACS_LANTERN", "ACS_BLOCK", "ACS_S3", "ACS_S7", "ACS_LEQUAL", "ACS_GEQUAL", "ACS_PI", "ACS_NEQUAL", "ACS_STERLING" }; int rows = 5, page=0, i, j, flag=0; int acs_nr = sizeof(acs_symbol) / sizeof(chtype); for(j=0; j<=acs_nr/rows; j++) { clear (); for(i=0; i<rows; i++) { if(page*rows+i <= acs_nr-1) { mvaddch(i*2+1, 3, acs_symbol[page*rows + i]); mvaddstr(i*2+1, 8, acs_name[page*rows + i]); } else { flag=1; } } if(!flag) { mvaddstr(rows*2 +2, 1, "Taste drücken -> nächste Seite"); } else { mvaddstr(rows*2 +2, 1, "Taste drücken -> Ende"); } refresh(); page++; getch(); } } void quit(void) { endwin(); } int main(void) { initscr(); atexit(quit); noecho(); curs_set(0); write_pages(); return(0); }
Fenster löschen
[Bearbeiten]Der durch ein Fenster belegte Speicherplatz kann über die Funktion
int delwin(WINDOW *win);
wieder freigegeben werden. Auf die Bildschirmdarstellung hat das vorerst keinen Einfluss. Natürlich sollte danach nicht mehr auf das gelöschte Fenster zugegriffen werden, da dies in aller Regel einen Programmabsturz infolge "Speicherzugriffsfehler" auslöst.
Fenster refreshen
[Bearbeiten]Zum Refreshen eines Fensters sind diese Funktionen vorgesehen:
int wrefresh(WINDOW *win); int wnoutrefresh(WINDOW *win); int doupdate(void);
Welche Funktion soll wann Verwendung finden?
Die einfachste Möglichkeit ist der Aufruf von wrefresh
. Diese Funktion bringt den gewünschten Fensterinhalt auf den real existierenden Bildschirm. wrefresh
besteht im Prinzip aus der sequentiellen Abfolge der Funktionen:
wnoutrefresh
... kopiert den gewünschten Fensterinhalt in den virtuellen Bildschirmspeicher.doupdate
... gleicht virtuellen Bildschirmspeicher mit dem realen Bildschirminhalt ab und vollzieht das Update.
Sind viele Fenster gleichzeitig zu refreshen, dann ist die wrefresh
-Funktion ineffizient. In diesem Fall ist es besser, zuerst alle Fenster mit einem wnoutrefresh
zu aktualisieren und am Ende nur einmal die doupdate
-Funktion aufzurufen.
Touch und Untouch
[Bearbeiten]Wird der Fensterinhalt geändert, dann wird das Fenster automatisch als "touched" (berührt) markiert. Die refresh-Funktion erkennt daran, dass das Fenster aktualisiert werden muss. Als "untouched" markierte Fenster werden bei Refreshs nicht aktualisiert, da aus Performancegründen virtueller und physikalischer Screen abgeglichen und nur die Änderungen übertragen werden. Ein Fenster kann auch manuell wieder als "untouched" markiert werden.
int touchwin(WINDOW *win); int untouchwin(WINDOW *win); bool is_wintouched(WINDOW *win);
Beispiel
[Bearbeiten]
Ncurses-Fenster sind gut verwendbar, solange sie nebeneinander platziert sind. Überlappen sich Fenster jedoch, dann kann es kompliziert werden. Aus diesem Grund kennt ncurses sogenannte Panels. Diese bieten Mechanismen, Fenster auch in z-Richtung zu verwalten. Panels gehören zwar zu ncurses, sind aber in eine eigene Bibliotheksdatei ausgelagert.
Ein neues Panel erzeugen:
PANEL *new_panel(WINDOW *win);
Reservierten Panel- Speicherplatz freigeben:
int del_panel(PANEL *pan);
Panelanzeige manipulieren:
int bottom_panel(PANEL *pan); // Panel nach hinten verschieben int top_panel(PANEL *pan); // Panel in den Vordergrund holen int show_panel(PANEL *pan); // Panel anzeigen int hide_panel(PANEL *pan); // Panel verstecken
Vorne-, hintenliegendes Panel eruieren (pan=0
: top bzw. bottom):
PANEL *panel_above(const PANEL *pan) PANEL *panel_below(const PANEL *pan)
Panels updaten:
void update_panels();
Beispiel
[Bearbeiten]#include <panel.h> #include <stdlib.h> WINDOW *win1, *win2; PANEL *pan1, *pan2; void quit(void) { del_panel(pan1); del_panel(pan2); delwin(win1); delwin(win2); endwin(); } int main(void) { int flag=0; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, 1); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLACK, COLOR_WHITE); init_pair(3, COLOR_BLACK, COLOR_YELLOW); win1 = newwin(10, 25, 5, 10); win2 = newwin(10, 25, 10, 15); box(win1, ACS_VLINE, ACS_HLINE); box(win2, ACS_VLINE, ACS_HLINE); pan1 = new_panel(win1); pan2 = new_panel(win2); bkgd(COLOR_PAIR(1)); wbkgd(win1, COLOR_PAIR(2)); wbkgd(win2, COLOR_PAIR(3)); mvaddstr(2,4, "F9 beendet das Programm"); mvwaddstr(win1, 2, 3, "Drücke eine Taste"); mvwaddstr(win2, 7, 3, "Drücke eine Taste"); update_panels(); doupdate(); while(getch() != KEY_F(9)) { if (flag==0) { top_panel(pan1); flag = 1; } else { top_panel(pan2); flag = 0; } update_panels(); doupdate(); } return (0); }
Compilieren, Linken:
gcc -o bsp bsp.c -lpanel -lncurses
Ein ncurses-Menü ist ein Menü in der ursprünglichen Bedeutung, also eine einfache Auswahlbox. Allerdings bietet auch die menu-Bibliothek genügend Möglichkeiten um diese Auswahlboxen sehr schön und sinnvoll auszugestalten.
Ein Menü erzeugen und wieder löschen
[Bearbeiten]Die Erzeugung eines Menüs untergliedert sich in folgende Schritte:
- Speicherplatz für die Items (Menüeinträge) reservieren:
calloc
-Funktion - Items erzeugen:
ITEM *new_item(const char *name, const char *description);
- Menü erzeugen:
MENU *new_menu(ITEM **items);
- Menü "posten" (post = anheften, ankleben -> "PostIt") :
int post_menu(MENU *menu);
Das "Abbauen" eines Menüs geschieht in umgekehrter Reihenfolge:
- Menü "unposten":
int unpost_menu(MENU *menu);
- Menü freigeben:
int free_menu(MENU *menu);
- Items freigeben:
int free_item(ITEM *item);
- Reservierten Items-Speicherplatz freigeben:
free
-Funktion
Der Menü-Treiber
[Bearbeiten]Eingabeereignisse für das Menü können mit der Funktion
int menu_driver(MENU *menu, int c);
abgehandelt werden.
Der Parameter c
bstimmt, welche Menüaktion durchgeführt werden soll:
REQ_LEFT_ITEM | bewegt den Menücursor um einen Eintrag nach links |
REQ_RIGHT_ITEM | bewegt den Menücursor um einen Eintrag nach rechts |
REQ_UP_ITEM | bewegt den Menücursor um einen Eintrag nach oben |
REQ_DOWN_ITEM | bewegt den Menücursor um einen Eintrag nach unten |
REQ_SCR_ULINE | eine Zeile aufwärts scrollen |
REQ_SCR_DLINE | eine Zeile abwärts scrollen |
REQ_SCR_UPAGE | eine Seite aufwärts scrollen |
REQ_SCR_DPAGE | eine Seite abwärts scrollen |
REQ_FIRST_ITEM | bewegt den Menücursor zum ersten Eintrag |
REQ_LAST_ITEM | bewegt den Menücursor zum letzten Eintrag |
REQ_NEXT_ITEM | bewegt den Menücursor zum nächsten Eintrag |
REQ_PREV_ITEM | bewegt den Menücursor zum vorherigen Eintrag |
REQ_TOGGLE_ITEM | An- oder abwählen eines Eintrags |
REQ_CLEAR_PATTERN | Suchmusterpuffer löschen |
REQ_BACK_PATTERN | Das vorherige Zeichen aus dem Suchmusterpuffer löschen |
REQ_NEXT_MATCH | Menücursor zum nächsten Eintrag, der zum Suchmuster passt, bewegen |
REQ_PREV_MATCH | Menücursor zum vorigen Eintrag, der zum Suchmuster passt, bewegen |
Den aktuell angewählten Menüeintrag ermitteln
[Bearbeiten]ITEM *current_item(const MENU *menu); int item_index(const ITEM *item);
Beispiel
[Bearbeiten]#include <menu.h> #include <stdlib.h> ITEM **it; MENU *me; void quit(void) { int i; unpost_menu(me); free_menu(me); for(i=0; i<=4; i++) { free_item(it[i]); } free(it); endwin(); } int main(void) { int ch; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); nl(); keypad(stdscr, TRUE); it = (ITEM **)calloc(5, sizeof(ITEM *)); it[0] = new_item("M1", ""); it[1] = new_item("M2", ""); it[2] = new_item("M3", ""); it[3] = new_item("Ende", ""); it[4] = 0; me = new_menu(it); post_menu(me); mvaddstr(7, 3, "Programm mittels Menü oder F1-Funktionstaste beenden"); refresh(); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: menu_driver(me, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(me, REQ_UP_ITEM); break; case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */ if(item_index(current_item(me)) == 3) exit(0); } } return (0); }
Compilieren, Linken:
gcc -o bsp bsp.c -lmenu -lncurses
Das Menü formatieren
[Bearbeiten]Ein Menü ist standardmäßig bis zu 16 Zeilen hoch und 1 Spalte breit. Zur Einstellung einer anderen Größe, z.B. zur Generierung eines mehrspaltigen Menüs, existiert die Funktion
int set_menu_format(MENU *menu, int rows, int cols);
Diese Funktion muss im Bedarfsfall aufgerufen werden, bevor das Menu gepostet wird.
Beispiel
[Bearbeiten]#include <menu.h> #include <stdlib.h> ITEM **it; MENU *me; void quit(void) { int i; unpost_menu(me); free_menu(me); for(i=0; i<=4; i++) { free_item(it[i]); } free(it); endwin(); } int main(void) { int ch; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); nl(); keypad(stdscr, TRUE); it = (ITEM **)calloc(5, sizeof(ITEM *)); it[0] = new_item("M1", ""); it[1] = new_item("M2", ""); it[2] = new_item("M3", ""); it[3] = new_item("Ende", ""); it[4] = 0; me = new_menu(it); set_menu_format(me, 2, 2); post_menu(me); mvaddstr(7, 3, "Programm mittels Menü oder F1-Funktionstaste beenden"); refresh(); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: menu_driver(me, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(me, REQ_UP_ITEM); break; case KEY_RIGHT: menu_driver(me, REQ_RIGHT_ITEM); break; case KEY_LEFT: menu_driver(me, REQ_LEFT_ITEM); break; case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */ if(item_index(current_item(me)) == 3) exit(0); } } return (0); }
Das Markierungssymbol
[Bearbeiten]Zwecks besserer Sichtbarkeit wird vor dem ausgewählten Menüeintrag zusätzlich ein Zeichen oder eine Zeichenkette als Markierungssymbol gesetzt. Normalerweise ist dies ein Bindestrich. Dieses Verhalten kann aber mit der Funktion
int set_menu_mark(MENU *menu, const char *mark);
geändert werden. Diese Funktion wird nur dann das gewünschte Resultat liefern, wenn sie vor dem Posten des Menüs aufgerufen wird.
Beispiel (Programmausschnitt)
[Bearbeiten]// ... set_menu_mark(me, "-->"); post_menu(me); // ...
Beispiel (Programmausschnitt)
[Bearbeiten]// Ausschalten des Markierungssysmbols //... set_menu_mark(me, ""); post_menu(me); // ...
Das Markierungssymbol sollte aber nur dann ausgeschaltet werden, wenn absolut sichergestellt ist, dass das Programm nur auf Terminals mit "Highlighting"- oder Farbunterstützung eingesetzt wird. Das "Erraten" der jeweiligen Menücursorposition kann sich sonst sehr nervenaufreibend gestalten.
Menüfenster
[Bearbeiten]Jedes Menü kann mit einem Haupt- und Unterfenster verknüpft werden. Das Hauptfenster kann z.B. zur Aufnahme eines Menütitels und zur Umrahmung des Unterfensters dienen. Im Unterfenster werden die Menüeinträge dargestellt.
int set_menu_win(MENU *menu, WINDOW *win); int set_menu_sub(MENU *menu, WINDOW *sub);
Werden diese Funktionen in einem Programm nicht eingesetzt, so sind die Menüs mit dem Standardscreen verbunden.
Beispiel
[Bearbeiten]#include <menu.h> #include <stdlib.h> ITEM **it; MENU *me; WINDOW *win; void quit(void) { int i; unpost_menu(me); free_menu(me); for(i=0; i<=4; i++) { free_item(it[i]); } free(it); delwin(win); endwin(); } int main(void) { int ch; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); nl(); keypad(stdscr, TRUE); it = (ITEM **)calloc(5, sizeof(ITEM *)); it[0] = new_item("M1", "Menueeintrag 1"); it[1] = new_item("M2", "Menueeintrag 2"); it[2] = new_item("M3", "Menueeintrag 3"); it[3] = new_item("Ende", "Programm beenden"); it[4] = 0; me = new_menu(it); win = newwin(8, 30, 5, 5); set_menu_win (me, win); set_menu_sub (me, derwin(win, 4, 28, 3, 2)); box(win, 0, 0); mvwaddstr(win, 1, 2, "***** Testmenü *****"); post_menu(me); mvaddstr(14, 3, "Programm mittels Menü oder F1-Funktionstaste beenden"); refresh(); wrefresh(win); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: menu_driver(me, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(me, REQ_UP_ITEM); break; case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */ if(item_index(current_item(me)) == 3) exit(0); } wrefresh(win); } return (0); }
Die minimal notwendige Größe eines Unterfensters kann über die Funktion
int scale_menu(const MENU *menu, int *rows, int *columns);
ermittelt werden.
Menüs bunt gestalten
[Bearbeiten]Die Farbgebung und Darstellungsattribute des selektierten Items festlegen:
int set_menu_fore(MENU *menu, chtype attr);
Die Farbgebung und Darstellungsattribute der unselektierten Items festlegen:
int set_menu_back(MENU *menu, chtype attr);
Das Erscheinungsbild des Menühauptfensters kann natürlich über die konventionellen ncurses-Befehle (wbkgd, wattrset
, etc.) gestaltet werden.
Beispiel
[Bearbeiten]#include <menu.h> #include <stdlib.h> ITEM **it; MENU *me; WINDOW *win; void quit(void) { int i; unpost_menu(me); free_menu(me); for(i=0; i<=4; i++) { free_item(it[i]); } free(it); delwin(win); endwin(); } int main(void) { int ch; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); nl(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_YELLOW); bkgd(COLOR_PAIR(1)); it = (ITEM **)calloc(5, sizeof(ITEM *)); it[0] = new_item("M1", "Menueeintrag 1"); it[1] = new_item("M2", "Menueeintrag 2"); it[2] = new_item("M3", "Menueeintrag 3"); it[3] = new_item("Ende", "Programm beenden"); it[4] = 0; me = new_menu(it); win = newwin(8, 30, 5, 5); set_menu_win (me, win); set_menu_sub (me, derwin(win, 4, 28, 3, 2)); box(win, 0, 0); mvwaddstr(win, 1, 2, "***** Testmenü *****"); set_menu_fore(me, COLOR_PAIR(1)|A_REVERSE); set_menu_back(me, COLOR_PAIR(1)); wbkgd(win, COLOR_PAIR(2)); post_menu(me); mvaddstr(14, 3, "Programm mittels Menü oder F1-Funktionstaste beenden"); refresh(); wrefresh(win); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: menu_driver(me, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(me, REQ_UP_ITEM); break; case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */ if(item_index(current_item(me)) == 3) exit(0); } wrefresh(win); } return (0); }
Optionen für Menüeinträge
[Bearbeiten]int set_item_opts(ITEM *item, OPTIONS opts); int item_opts_on(ITEM *item, OPTIONS opts); int item_opts_off(ITEM *item, OPTIONS opts);
Die Funktionsbezeichnungen sind selbsterklärend. Es gibt hier nur eine Option, nämlich
O_SELECTABLE
Wird die Selektierbarkeit für einen Menüeintrag hiermit ausgeschaltet, so ist dieser Menüeintrag als nicht selektierbar dargestellt. Dies bezieht sich aber nur auf die Menüdarstellung, das Item ist trotzdem immer noch auswählbar. Die "Nichtselektierbarkeit" eines Items muss vom Programmierer im weiteren Code berücksichtigt werden. Möglich ist dies durch die Abfrage der Itemoptionen
OPTIONS item_opts(const ITEM *item);
Die Farbgebung für derartige nicht selektierbare Items kann über die Funktion
int set_menu_grey(MENU *menu, chtype attr);
gesteuert werden.
Beispiel
[Bearbeiten]#include <menu.h> #include <stdlib.h> ITEM **it; MENU *me; WINDOW *win; void quit(void) { int i; unpost_menu(me); free_menu(me); for(i=0; i<=4; i++) { free_item(it[i]); } free(it); delwin(win); endwin(); } int main(void) { int ch; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); nl(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_WHITE, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_YELLOW); init_pair(3, COLOR_BLACK, COLOR_BLUE); bkgd(COLOR_PAIR(1)); it = (ITEM **)calloc(5, sizeof(ITEM *)); it[0] = new_item("M1", "Menueeintrag 1"); it[1] = new_item("M2", "Menueeintrag 2"); it[2] = new_item("M3", "Menueeintrag 3"); it[3] = new_item("Ende", "Programm beenden"); it[4] = 0; item_opts_off(it[3], O_SELECTABLE); me = new_menu(it); win = newwin(8, 30, 5, 5); set_menu_win (me, win); set_menu_sub (me, derwin(win, 4, 28, 3, 2)); box(win, 0, 0); mvwaddstr(win, 1, 2, "***** Testmenü *****"); set_menu_fore(me, COLOR_PAIR(1)|A_REVERSE); set_menu_back(me, COLOR_PAIR(1)); set_menu_grey(me, COLOR_PAIR(3)); wbkgd(win, COLOR_PAIR(2)); post_menu(me); mvaddstr(14, 3, "Programm mittels F1-Funktionstaste beenden"); refresh(); wrefresh(win); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_DOWN: menu_driver(me, REQ_DOWN_ITEM); break; case KEY_UP: menu_driver(me, REQ_UP_ITEM); break; case 0xA: /* Return- bzw. Enter-Taste -> ASCII-Code */ if(item_index(current_item(me))==3 && item_opts(current_item(me))==O_SELECTABLE) exit(0); } wrefresh(win); } return (0); }
Menüoptionen
[Bearbeiten]Zum Setzen von Menüoptionen werden diese Funktionen verwendet:
int set_menu_opts(MENU *menu, OPTIONS opts); int menu_opts_on(MENU *menu, OPTIONS opts); int menu_opts_off(MENU *menu, OPTIONS opts);
Einige der verfügbaren Optionswerte sind
O_SHOWDESC |
Beschreibungen zu den Einträgen anzeigen |
O_NONCYCLIC |
Nicht-zyklisch, am Menüende nicht automatisch zum Menübeginn springen und umgekehrt |
O_ONEVALUE |
Nur ein Menüeintrag ist auswählbar |
Alle Optionen sind standardmäßig eingeschaltet.
Beispiel: O_SHOWDESC
[Bearbeiten]// ... menu_opts_off(me, O_SHOWDESC); // ...
Beispiel: Mehrfachauswahl
[Bearbeiten]Bei einer möglichen Mehrfachauswahl kann nicht mehr einfach mittels current_item
der ausgewählte Menüeintrag bestimmt werden. Stattdessen kann die Funktion
bool item_value(const ITEM *item);
Verwendung finden. Diese Funktion liefert für selektierte Menüeinträge TRUE
, für unselektierte Menüeinträge FALSE
.
// ... menu_opts_off(me, O_ONEVALUE); // ... while((ch=getch()) != KEY_F(1)) { switch(ch) { // ... case 0x20: /* Leertaste */ menu_driver(me, REQ_TOGGLE_ITEM); int i; for(i=0; i<4; i++) { mvprintw(16+i, 3, "Item %i: %i", i+1, item_value(it[i])); } break; // ... } } //...
Damit sind die ncurses-Menüs zwar bei weitem noch nicht umfassend abgehandelt. Jedoch wären weitere Themen teilweise schon sehr komplex und nur für spezielle Einsatzfälle wirklich interessant. Mit dieser Bemerkung soll dieses Kapitel hier vorerst abgeschlossen werden.
Ein Formular erzeugen und wieder löschen
[Bearbeiten]Der Auf- und Abbau von Formularen folgt dem gleichen Prinzip wie bei Menüs.
Die Erzeugung eines Formulars untergliedert sich in folgende Schritte:
- Speicherplatz für die Formularfelder reservieren: z.B. mittels
calloc
-Funktion - Formularfelder erzeugen:
FIELD *new_field(int height, int width, int toprow, int leftcol, int offscreen, int nbuffers);
FIELD *dup_field(FIELD *field, int toprow, int leftcol);
FIELD *link_field(FIELD *field, int toprow, int leftcol);
- Formular erzeugen:
FORM *new_form(FIELD **fields);
- Formular "posten":
int post_form(FORM *form);
Zu beachten ist, dass das letzte Formularfeld zwingend ein Null-Pointer sein muss.
Das "Abbauen" eines Formulars geschieht in umgekehrter Reihenfolge:
- Formular "unposten":
int unpost_form(FORM *form);
- Formular freigeben:
int free_form(FORM *form);
- Felder freigeben:
int free_field(FIELD *field);
- Reservierten Feld-Speicherplatz freigeben:
free
-Funktion
Der Formulartreiber
[Bearbeiten]Eingabeereignisse für ein Formular werden durch den Formulartreiber abgearbeitet.
int form_driver(FORM *form, int c);
Welche Aktion konkret ausgeführt werden soll, wird durch den Parameter c
bestimmt. Eine schiere Unzahl von Optionen ist verfügbar. Nachfolgend werden nur ein paar dieser Request-Optionen aufgelistet:
REQ_NEXT_FIELD | Cursor zum nächsten Feld bewegen |
REQ_PREV_FIELD | Cursor zum vorherigen Feld bewegen |
REQ_FIRST_FIELD | Cursor zum ersten Feld bewegen |
REQ_LAST_FIELD | Cursor zum letzten Feld bewegen |
REQ_BEG_LINE | Cursor zum Zeilenanfang bewegen |
REQ_END_LINE | Cursor zum Zeilenende bewegen |
REQ_LEFT_CHAR | Cursor im Feld nach links bewegen |
REQ_RIGHT_CHAR | Cursor im Feld nach rechts bewegen |
REQ_UP_CHAR | Cursor im Feld nach oben bewegen |
REQ_DOWN_CHAR | Cursor im Feld nach unten bewegen |
REQ_INS_CHAR | An der Cursorposition ein Leerzeichen einfügen |
REQ_DEL_CHAR | An der Cursorposition ein Zeichen löschen |
REQ_DEL_PREV | Das Zeichen vor der Cursorposition löschen |
REQ_CLR_FIELD | Das ganze Formularfeld löschen |
REQ_OVL_MODE | Überschreibmodus aktivieren |
REQ_INS_MODE | Einfügemodus aktivieren |
Feldfarben und andere Darstellungsattribute
[Bearbeiten]Hintergrundattribute festlegen:
int set_field_fore(FIELD *field, chtype attr);
Vordergrundattribute festlegen:
int set_field_back(FIELD *field, chtype attr);
Beispiel
[Bearbeiten]#include <form.h> #include <stdlib.h> FIELD **fi; FORM *fo; void quit(void) { int i; unpost_form(fo); free_form(fo); for(i=0; i<=3; i++) { free_field(fi[i]); } free(fi); endwin(); } int main(void) { int ch, i; initscr(); atexit(quit); clear(); noecho(); cbreak(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLACK, COLOR_WHITE); bkgd(COLOR_PAIR(1)); fi = (FIELD **)calloc(4, sizeof(FIELD *)); fi[0] = new_field(1, 10, 2, 3, 0, 0); fi[1] = new_field(1, 10, 2, 18, 0, 0); fi[2] = new_field(1, 15, 2, 33, 0, 0); fi[3] = 0; for(i=0; i<3; i++) { set_field_fore(fi[i], COLOR_PAIR(2)); set_field_back(fi[i], COLOR_PAIR(2)); } fo = new_form(fi); post_form(fo); mvaddstr(2, 15, "+"); mvaddstr(2, 30, "="); mvaddstr(5, 3, "Programm mittels F1-Funktionstaste beenden"); refresh(); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_RIGHT: form_driver(fo, REQ_NEXT_FIELD); break; case KEY_LEFT: form_driver(fo, REQ_PREV_FIELD); break; default: /* Feldeingabe */ form_driver(fo, ch); } } return (0); }
Compilieren, Linken:
gcc -o bsp bsp.c -lform -lncurses
Zugriff auf den Formularfeldpuffer
[Bearbeiten]Auf ein bestimmtes Feld zugreifen:
FIELD *current_field(const FORM *); int field_index(const FIELD *field);
Feldpuffer auslesen:
char *field_buffer(const FIELD *field, int buffer);
Feldpuffer belegen:
int set_field_buffer(FIELD *field, int buf, const char *value);
Beispiel
[Bearbeiten]#include <form.h> #include <stdlib.h> #include <string.h> FIELD **fi; FORM *fo; void quit(void) { int i; unpost_form(fo); free_form(fo); for(i=0; i<=3; i++) { free_field(fi[i]); } free(fi); endwin(); } int main(void) { int ch, i; initscr(); atexit(quit); clear(); noecho(); cbreak(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLACK, COLOR_WHITE); bkgd(COLOR_PAIR(1)); fi = (FIELD **)calloc(4, sizeof(FIELD *)); fi[0] = new_field(1, 10, 2, 3, 0, 0); fi[1] = new_field(1, 10, 2, 18, 0, 0); fi[2] = new_field(1, 15, 2, 33, 0, 0); fi[3] = 0; for(i=0; i<3; i++) { set_field_fore(fi[i], COLOR_PAIR(2)); set_field_back(fi[i], COLOR_PAIR(2)); } fo = new_form(fi); post_form(fo); mvaddstr(2, 15, "+"); mvaddstr(2, 30, "="); mvaddstr(5, 3, "Programm mittels F1-Funktionstaste beenden"); refresh(); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_RIGHT: { char str[20]; form_driver(fo, REQ_NEXT_FIELD); if(field_index(current_field(fo)) == 2) { snprintf(str, 20, "%s%s", field_buffer(fi[0], 0), field_buffer(fi[1], 0)); set_field_buffer(fi[2], 0, str); refresh(); } break; } case KEY_LEFT: form_driver(fo, REQ_PREV_FIELD); break; default: /* Feldeingabe */ form_driver(fo, ch); } } return (0); }
Textausrichtung
[Bearbeiten]Die Ausrichtung eines Textes im Formularfeld ist mittels
int set_field_just(FIELD *field, int justification);
einstellbar.
Mögliche Ausrichtungsoptionen sind:
- JUSTIFY_RIGHT
- JUSTIFY_LEFT
- JUSTIFY_CENTER
- NO_JUSTIFICATION
Beispiel (Programmausschnitt)
[Bearbeiten]// ... set_field_fore(fi[i], COLOR_PAIR(2)); set_field_back(fi[i], COLOR_PAIR(2)); set_field_just(fi[i], JUSTIFY_RIGHT); // ...
Feldoptionen
[Bearbeiten]Selbstverständlich gibt es auch für Formularfelder ein Menge Optionen. Gesetzt und abgefragt werden können sie mit diesen Funktionen:
int set_field_opts(FIELD *field, OPTIONS opts); int field_opts_on(FIELD *field, OPTIONS opts); int field_opts_off(FIELD *field, OPTIONS opts); OPTIONS field_opts(const FIELD *field);
Einige der möglichen Optionen sind:
O_VISIBLE | Formularfeldsichtbarkeit |
O_ACTIVE | Feld ist aktiv |
O_PUBLIC | Text ist bei der Eingabe sichtbar (z.B. bei Passworteingaben diese Option deaktivieren) |
O_EDIT | Im Feld kann editiert werden |
O_WRAP | Zeilenumbbruch |
O_AUTOSKIP | Wenn Feld vollgeschrieben ist, gehe automatisch zum nächsten Feld |
O_STATIC | Ein Feld kann nur die Zeichenanzahl entsprechend der Formularfeldgröße aufnehmen. Werden mehr Zeichen eingegeben so wird zum nächsten Formularfeld gesprungen. Ist O_AUTOSKIP deaktiviert, so werden zusätzliche Zeichen ignoriert. Ist O_STATIC ausgeschaltet, so kann das Formularfeld über die Formularfeldgröße Zeichen aufnehmen (die Darstellung wird gescrollt). |
Beispiel: Auswirkungen O_AUTOSKIP und O_STATIC
[Bearbeiten]Beim Eintippen der Zeichenkette "Das ist nicht OK" in ein Formularfeld passiert je nach gesetzten Optionen folgendes
O_AUTOSKIP an, O_STATIC an (Standard): | |
O_AUTOSKIP aus: | |
O_STATIC aus: |
Formularfeldtypen
[Bearbeiten]Oft ist es sinnvoll und notwendig die Eingabemöglichkeiten in ein Formularfeld einzuschränken (z.B. nur Zahlen oder alphabetische Zeichen sind erlaubt). Dies ist mit der form-Bibliothek recht weitgehend möglich. Mit der Funktion
int set_field_type(FIELD *field, FIELDTYPE *type, ...);
lassen sich die Feldtypen einstellen. Folgende Alternativen sind möglich
TYPE_ALPHA | nur Alphabetzeichen sind erlaubt |
TYPE_ALNUM | Alphanumerische Zeichen sind erlaubt |
TYPE_ENUM | Nur Einträge aus einer Stringliste sind erlaubt |
TYPE_INTEGER | Nur ganze Zahlen sind erlaubt (optional mit vorangestelltem + oder -) |
TYPE_NUMERIC | Numerische Daten (optional mit vorangestelltem + oder - und mit Dezimalpunkt) |
TYPE_REGEXP | Feldeintrag muss zu einem regulären Ausdruck passen |
TYPE_IPV4 | Eine IPv4-Adresse |
Es können auch eigene Formularfeldtypen festgelegt werden. Die Abhandlung dieses Themas würde jedoch im Rahmen dieses Tutorials zu weit führen. Nachfolgend ein einfaches Beispiel mit INTEGER- und NUMERIC-Formularfeldern.
Beispiel
[Bearbeiten]#include <form.h> #include <stdlib.h> FIELD **fi; FORM *fo; void quit(void) { int i; unpost_form(fo); free_form(fo); for(i=0; i<=3; i++) { free_field(fi[i]); } free(fi); endwin(); } int main(void) { int ch, i; initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, TRUE); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLACK, COLOR_WHITE); bkgd(COLOR_PAIR(1)); fi = (FIELD **)calloc(4, sizeof(FIELD *)); fi[0] = new_field(1, 10, 2, 3, 0, 0); fi[1] = new_field(1, 10, 2, 18, 0, 0); fi[2] = new_field(1, 15, 2, 33, 0, 0); fi[3] = 0; for(i=0; i<3; i++) { set_field_fore(fi[i], COLOR_PAIR(2)); set_field_back(fi[i], COLOR_PAIR(2)); field_opts_off(fi[i], O_AUTOSKIP); } set_field_type(fi[0], TYPE_INTEGER, 0, -9999999, 9999999); set_field_type(fi[1], TYPE_NUMERIC, 3, -9999999.999, 9999999.999); field_opts_off(fi[2], O_EDIT); fo = new_form(fi); post_form(fo); mvaddstr(2, 15, "+"); mvaddstr(2, 30, "="); mvaddstr(5, 3, "Programm mittels F1-Funktionstaste beenden"); refresh(); while((ch=getch()) != KEY_F(1)) { switch(ch) { case KEY_RIGHT: { double z1, z2; char str[20]; form_driver(fo, REQ_NEXT_FIELD); if(field_index(current_field(fo)) == 2) { z1 = atof(field_buffer(fi[0], 0)); z2 = atof(field_buffer(fi[1], 0)); snprintf(str, 20, "%f", z1+z2); set_field_buffer(fi[2], 0, str); refresh(); } break; } case KEY_LEFT: form_driver(fo, REQ_PREV_FIELD); break; default: /* Feldeingabe */ form_driver(fo, ch); } } return (0); }
Formularfenster
[Bearbeiten]Das Zuweisen von Haupt- und Unterfenster geschieht äquivalent der Vorgehensweise bei einem Menü.
int set_form_win(FORM *form, WINDOW *win); int set_form_sub(FORM *form, WINDOW *sub); int scale_form(const FORM *form, int *rows, int *columns);
Ncurses bietet Mausunterstützung. Standardmäßig ist diese Funktionalität deaktiviert. Zur Aktivierung ist die Funktion
mmask_t mousemask(mmask_t newmask, mmask_t *oldmask);
mit der gewünschten Bitmaske aufzurufen. Vordefinierte Masken sind (auszugsweise):
ALL_MOUSE_EVENTS | Alle möglichen Mausereignisse |
REPORT_MOUSE_POSITION | Mausposition melden |
BUTTON1_CLICKED | Maustaste 1 geklickt |
BUTTON1_DOUBLE_CLICKED | Maustaste 1 doppelgeklickt |
BUTTON2_CLICKED | Maustaste 2 geklickt |
BUTTON2_DOUBLE_CLICKED | Maustaste 2 doppelgeklickt |
BUTTON3_CLICKED | Maustaste 3 geklickt |
BUTTON3_DOUBLE_CLICKED | Maustaste 3 doppelgeklickt |
BUTTON_SHIFT | Zusätzlich SHIFT-Taste gedrückt |
BUTTON_CTRL | Zusätzlich STRG-Taste gedrückt |
BUTTON_ALT | Zusätzlich ALT-Taste gedrückt |
Die Abfrage des Auftretens eines durch die Mausmaske festgelegten sichtbaren Mausereignisses kann durch
int getmouse(MEVENT *event);
erfolgen.
Beispiel
[Bearbeiten]#include <ncurses.h> #include <stdlib.h>
MEVENT *mev;
void quit(void)
{
free(mev);
endwin();
}
int main(void)
{
int ch;
mev = (MEVENT *)malloc(sizeof(MEVENT));
initscr();
atexit(quit);
clear();
noecho();
curs_set(0);
cbreak();
keypad(stdscr, TRUE);
start_color();
mousemask(BUTTON1_CLICKED, 0);
init_pair(1, COLOR_YELLOW, COLOR_BLUE); bkgd(COLOR_PAIR(1)); mvaddstr(5, 3, „Programm durch anklicken der Maustaste 1 beenden“); refresh();
for(;;) { ch=getch();
switch(ch) { case KEY_MOUSE: { if(getmouse(mev) == OK) { exit(0); } } } } return (0); }
Ein Pad (Schreibblock) ist eine Variante des konventionellen ncurses-Fensters. In der Anwendung unterscheidet es sich deutlich von diesem. Pads können größer als der Screen selbst sein und der Programmierer entscheidet erst beim Refresh, welcher Teil des Pads wo sichtbar ist.
Ein Pad erstellen
[Bearbeiten]WINDOW *newpad(int nlines, int ncols);
Bedeutung der Parameter:
nlines, ncols
... Anzahl der Pad-Zeilen und -Spalten
Ein Pad refreshen
[Bearbeiten]int prefresh(WINDOW *pad, int pminrow, int pmincol, int sminrow, int smincol, int smaxrow, int smaxcol); int pnoutrefresh(WINDOW *pad, int pminrow, int pmincol, int sminrow, int smincol, int smaxrow, int smaxcol);
Die Pad-Refreshfunktionen haben prinzipiell dieselben Aufgaben wie ihre Window-Pendants.
Bedeutung der Parameter:
pminrow, pmincol
... Ecke links-oben im Pad (p ... pad).sminrow, smincol, smaxrow, smaxcol
... Ecke links-oben, Ecke rechts-unten. Diese Parameter bestimmen die Größe des auf dem Screen angezeigten Pad-Rechtecks, innerhalb dessen der Pad-Inhalt dargestellt wird (s ... screen).
Beispiel
[Bearbeiten]#include <curses.h> #include <stdlib.h> WINDOW *pad; void quit(void) { delwin(pad); endwin(); } int main(void) { initscr(); atexit(quit); clear(); noecho(); curs_set(0); cbreak(); keypad(stdscr, 1); start_color(); init_pair(1, COLOR_YELLOW, COLOR_BLUE); init_pair(2, COLOR_BLUE, COLOR_WHITE); pad = newpad(300, 100); bkgd(COLOR_PAIR(1)); wbkgd(pad, COLOR_PAIR(2)); waddstr(pad, "Zeile 1 \n"); waddstr(pad, "Zeile 2\n"); waddstr(pad, "Diese Zeichenkette befindet sich in Zeile 3\n"); waddstr(pad, "und diese in Zeile 4"); refresh(); prefresh(pad, 0, 0, 3, 3, 10, 30); getch(); refresh(); prefresh(pad, 2, 2, 12, 2, 20, 45); while(getch() != KEY_F(1)) { } return(0); }
Nach dem Programmstart | Nach dem ersten Tastendruck |
---|---|
Jedes einzelne Kapitel könnte noch beliebig erweitert werden. Viele ncurses-Funktionen passend zu den einzelnen Kapiteln wurden überhaupt nicht erwähnt. Aber dieses Buch soll auch ein Tutorial darstellen und kein Referenzhandbuch. Vieles von dem, was gezeigt wurde lässt sich sicher auch effizienter und kompakter codieren. Die Beispiele wurden möglichst einfach gehalten und sollen dem grundlegenden Verständnis dienen. Dementsprechend fehlen praxisbezogene Beispiele.
Welche Themen wurden komplett ausgespart?
- Die
intrflush()
-Funktion - User-Pointer
- Hook-Funktionen: z. B. für Menüs und Formulare.
- Diverse Utility-Funktionen
- Low-level-Funktionen für verschiedene spezielle ncurses-Fähigkeiten
- slk: soft function-key labels
Des Weiteren bietet ncurses auch Anbindungen an die Programmiersprachen Ada und C++. Interessant und hilfreich sind auch speziell auf curses aufbauende Widgetbibliotheken, wie z. B. CDK (Curses Development Kit).
Weitere Informationen zu ncurses
[Bearbeiten]- Thomas E. Dickey: ncurses-FAQ
- Free Software Foundation: Announcing ncurses
- invisible-island.net: ncurses
- Eric S. Raymond, Zeyd M. Ben-Halim: Writing Programs with NCURSES
- Pradeep Padala: NCURSES Programming HOWTO
- Reha K. Gerceker: Einführung in Ncurses
Downloadmöglichkeit
[Bearbeiten]Andere curses-Bibliotheken
[Bearbeiten]