Curses¶
Die C-Bibliothek Curses beziehungsweise ihre neuere Version NCurses bietet die Möglichkeit, textbasierte Benutzeroberflächen zu erzeugen. Curses wird daher in vielen Shell-Programmen verwendet, darunter aptitude, cmus, mc, usw.
Curses starten und beenden¶
Um Curses zu starten, muss zunächst die Funktion initscr()
aufgerufen
werden. Diese Funktion erzeugt einen leeres Fenster und weist ihm den Namen
stdscr
(„standard screen“) zu. Damit das neue Fenster angezeigt wird, muss
anschließend die Funktion refresh()
aufgerufen werden, so dass das
Shell-Fenster aktualisiert wird und die Änderungen sichtbar werden.
Mit der refresh()
-Anweisung werden in Curses zwei Teilfunktionen aufgerufen:
Zunächst werden mittels der ersten Funktion wnoutrefresh()
nur die
veränderten Teile eines Curses-Fensters in einem „virtuellen“ Fenster
aktualisiert. Anschließend wird dieses mittels der zweiten Funktion
douptate()
auf den Bildschirm übertragen. Somit wird immer nur der Teil des
Fensters aktualisiert, der tatsächlich verändert wurde; dies ist wesentlich
effizienter, als wenn ständig das gesamte Shell-Fenster aktualisiert werden
müsste.
Um ein Curses-Programm wieder zu beenden, verwendet man die Funktion
endwin()
. Diese löscht den Bildschirm und stellt automatisch die
vorgefundenen Shell-Einstellungen wieder her. Da endwin()
insgesamt
zahlreiche Aufräumarbeiten übernimmt, sollte Curses stets mit dieser Funktion
beendet werden.
Ein minimales Curses-Programm, das nur kurz einen leeren Bildschirm erzeugt, auf diesem „Hallo Welt“ ausgibt und sich nach kurzer Zeit selbst beendet, kann folgendermaßen aussehen:
// Datei: curses-beispiel-1.c
#include <ncurses.h>
int main(void)
{
initscr();
printw("Hallo Welt!");
refresh();
napms(3000);
endwin();
return 0;
}
In diesem Beispiel wurde zudem die Curses-Funktion napms()
verwendet, die
eine weitere Ausführung des Programms um die angegebene Anzahl in Millisekunden
verzögert.
Ausgeben und Einlesen von Text¶
Zur Ausgabe von Text gibt es in Curses im Wesentlichen drei Funktionen:
- Mittels
addch(c)
kann ein einzelnes Zeichen auf dem Bildschirm ausgegeben werden. - Mittels
addstr(*str)
kann eine ganze Zeichenkette auf dem Bildschirm ausgegeben werden. (Dabei wird intern die Funktionaddch()
aufgerufen, bis die Zeichenkette abgearbeitet ist.) - Mittels
printw()
kann Text in der gleichen Weise in einem Curses-Fenster ausgegeben werden, wie dies mittels der Funktion printf() auf dem Standard-Ausgang der Fall ist.
Damit der Text an der richtigen Stelle im Curses-Fenster erscheint, kann man
mittels der Funktion move()
den Cursor an eine bestimmte Stelle bewegen. Als
erstes Argument wird dabei die Zeilennummer y
, als zweites die
Spaltennummer x
angegeben, also move(y,x)
.[1] Da Curses, wie in C
üblich, bei der Nummerierung mit Null beginnt, entspricht move(0,0)
einem
Bewegen des Cursors in die obere linke Ecke; die erlauben Maximalwerte für die
Zeilen- und Spaltennummer in move()
sind entsprechend um kleiner
als die Zeilen- und Spaltenanzahl des Fensters. Diese beiden Werte können
mittels der Funktion getmaxyx(stdscr, maxrow, maxcol)
bestimmt werden, wobei
maxrow
und maxcol
im Voraus als int
deklariert werden müssen:[2]
// Datei: curses-beispiel-2.c
#include <ncurses.h>
int maxrow, maxcol;
int main(void)
{
initscr();
// Größe des Curses-Fensters bestimmen:
getmaxyx(stdscr, maxrow, maxcol);
// Größe des Curses-Fensters ausgeben:
move(0,0);
printw("Das Fenster hat %d Zeilen und %d Spalten.", maxrow, maxcol);
refresh();
napms(3000);
endwin();
return 0;
}
Die Kombination von move()
mit einer der Print-Anweisungen kommt in
Curses-Anwendungen sehr häufig vor; daher gibt es zu den drei Ausgabefunktionen
addch()
, addstr()
und printw()
auch die kombinierten Funktionen
mvaddch()
, mvaddstr()
und mvprintw()
. Diesen wird beim Aufruf
zunächst die gewünschte Position des Cursor angegeben, die übrigen Argumente
sind mit den Basisfunktionen identisch. Beispielsweise sind die folgenden beiden
Aufrufe identisch:
// Text in Zeile 0, Spalte 3 ausgeben:
move(0,3)
addstr("Hallo Curses!")
// Kurzschreibweise:
mvaddstr(0, 3, "Hallo Curses!")
Zur Eingabe von Text gibt es in Curses ebenfalls drei grundlegende Funktionen:
- Mittels
getch(c)
kann ein einzelnes Zeichen vom Bildschirm eingelesen werden; das Zeichen wird dabei automatisch eingelesen, ohne dass dieEnter
-Taste gedrückt werden muss. - Mittels
getstr(*str)
undgetnstr(*str, n)
kann eine ganze Zeichenkette vom Curses-Fenster eingelesen werden, wie es mit gets() von der Standard-Eingabe der Fall ist. Die Funktiongetnstr()
beschränkt die Anzahl an eingelesenen Zeichen dabei aufn
Stück, so dass sichergestellt werden kann, dass das Array, in dem die Zeichenkette abgelegt werden soll, ausreichend groß ist. - Mittels
scanw()
kann Text in der gleichen Weise von einem Curses-Fenster eingelesen werden, wie dies mittels der Funktion scanf() aus dem Standard-Eingang der Fall ist.
Als Standard geben alle Eingabefunktionen die vom Benutzer eingegebenen Zeichen
unmittelbar auf dem Bildschirm aus, auch ohne dass dazu die
refresh()
-Funktion aufgerufen werden müsste; zusätzlich stoppt das Programm,
bis die Eingabe vom Benutzer erfolgt ist. Ist dies nicht gewünscht, so müssen
diese Einstellung, wie im folgenden Abschnitt beschrieben, deaktiviert werden.
Modifizierung der Ein- und Ausgabe
In Curses gibt es folgende Funktionen, die das Verhalten des Programms hinsichtlich Eingabe und Ausgabe anzupassen:
raw()
undcbreak()
:Normalerweise speichert die Shell die Eingabe des Benutzers in einem Puffer, bis ein Neues-Zeile-Zeichen oder ein Carriage-Return-Zeichen (Enter-Taste) erscheint. Die meisten interaktiven Programme benötigen die eingegebenen Zeichen allerdings unmittelbar. Die beiden Funktionen
raw()
undcbreak()
deaktivieren beide das Puffern von eingegebenen Zeichen, wobei sie sich in einem Detail unterscheiden: Eingegebene Zeichen wieCtrl z
(„Suspend“) oderCtrl c
(„Interrupt“), die von der Shell normalerweise als Kontrollsequenzen interpretiert werden, werden auch bei der Verwendung voncbreak()
zunächst von der Shell ausgewertet. Bei Verwendung vonraw()
werden auch diese Zeichen direkt ans Programm weitergeleitet und dort interpretiert.
echo()
undnoecho()
:Diese beiden Funktionen beeinflussen, ob vom Benutzer eingegebene Zeichen unmittelbar auf dem Bildschirm erscheinen sollen oder nicht. Diese Funktionen sind insbesondere in Verbindung mit der Curses-Funktion getch() von Bedeutung, um beispielsweise in interaktiven Programmen die unnötige Wiedergabe der vom Benutzer gedrückten Tasten auf dem Bildschirm zu vermeiden. Meist wird
noecho()
zu Beginn des Programms aufgerufen, und der Echo-Modus nur im Bedarfsfall (beispielsweise beim zeichenweise Einlesen von Text) aktiviert.
keypad()
:Diese Funktion sollte von jedem interaktiven Curses-Programm aufgerufen werden, denn sie ermöglicht die Verwendung der Funktions- und Pfeiltasten. Um beispielsweise die Funktion für den Standard-Bildschirm
stdscr
zu aktivieren, gibt mankeypad(stdscr, TRUE);
ein.[3]
curs_set()
:Diese Funktion kann verwendet werden, um den Cursor unsichtbar oder wieder sichtbar zu machen. Mit
curs_set(0);
wird der Cursor unsichtbar, mitcurs_set(1);
wieder sichtbar.
halfdelay(n)
:Mit dieser nur in Ausnahmefällen verwendeten Funktion kann festgelegt werden, dass beim dem Einlesen eines Zeichens mittels getch() oder einer Zeichenkette maximal Zehntel Sekunden gewartet wird. Wird in dieser Zeit kein Text eingegeben, so fährt das Programm fort. Dies kann beispielsweise für eine Timeout-Funktion bei einer Passwort-Eingabe verwendet werden.
nodelay()
:Diese Funktion wird von den meisten interaktiven Curses-Programm zu Beginn aufgerufen, denn sie verhindert, dass das Programm bei der Verwendung der Funktion getch() anhält. Anstelle dessen liefert
getch()
kontinuierlich den WertERR
(entspricht dem Wert-1
) zurück, sofern der Benutzer keine Taste gedrückt hat.
Mit Hilfe von nodelay(stdscr, TRUE)
kann beispielsweise eine mainloop()
programmiert werden, die einzelne von der Tastatur aus eingegebene Zeichen über
eine switch-Anweisung mit bestimmten Anweisungen
verknüpft:[4]
// Datei: curses-beispiel-3.c
#include <ncurses.h>
int main()
{
int c;
int quit = FALSE;
initscr();
cbreak();
noecho();
keypad(stdscr, TRUE);
nodelay(stdscr, TRUE);
mvprintw(0,0, "Bitte Taste eingeben oder Programm mit \'q\' beenden.");
while( !quit )
{
c = getch();
switch(c)
{
case ERR:
napms(10);
break;
case 'q':
quit = TRUE;
break;
default:
mvprintw(3, 0, "ASCII-Code des Zeichens: %3d;", c);
mvprintw(3, 30, "Zeichen wird dargestellt als: \'%c\'.", c);
break;
}
refresh();
}
endwin();
return 0;
}
Im obigen Beispielprogramm wird zunächst Curses gestartet und das
Bildschirm-Verhalten angepasst. Anschließend wird mittels der
while
-Schleife kontinuierlich eine Tastatureingabe vom Benutzer abgefragt:
- Wird keine Taste gedrückt (Rückgabewert:
ERR
), so wartet das Programm durch Aufruf vonnapms(10)
zehn Millisekunden lang, bis es mit der Ausführung fortfährt. Ohne eine derartige Verzögerung würde das Programm die Schleife kontinuierlich mit maximaler Geschwindigkeit abarbeiten und somit ständig maximale CPU-Last verursachen; mit „nur“ zehn Millisekunden Pause reduziert sich die CPU-Auslastung auf circa . - Wird eine beliebige Taste außer
q
gedrückt, so wird der ASCII-Wert des Zeichens und das Zeichen selbst ausgegeben. Die Darstellung funktioniert nur bei alphabetischen und numerischen Zeichen wie gewohnt, bei Funktions- und Sondertasten kann zumindest der ASCII-Wert des eingegebenen Zeichens abgefragt werden. - Entspricht das eingegebene Zeichen dem Zeichen
q
(beziehungsweise dem ASCII-Wert113
), so wird die Variablequit
aufTRUE
gesetzt. Damit ist die Negation!quit
gleichFALSE
, und die Schleife wird nicht fortgesetzt.
Schließlich wird das Curses-Programm mittels endwin()
beendet.
Editor-Funktionen¶
Die Curses-Bibliothek stellt, da sie auf textbasierte Programme ausgerichtet ist, einige Funktionen bereit, die das Eingeben von Text ziemlich komfortabel gestalten.
Um einzelne Zeichen oder Zeilen einzugeben oder zu löschen, gibt es in Curses folgende Funktionen:
insch()
Mit
insch(c)
kann ein einzelnes Zeichen an der Stelle des Cursors eingefügt werden; der Rest der Zeile wird dabei automatisch um eine Zeichenbreite nach rechts verschoben.delch()
Mit
delch()
wird das Zeichen an der Stelle des Cursors gelöscht; der Rest der Zeile wird dabei automatisch um eine Zeichenbreite nach links verschoben.insertln()
Mit
insertln()
kann eine neue Zeile an der Stelle des Cursors eingefügt werden; alle folgenden Zeilen werden dabei automatisch um eine Zeile nach unten verschoben.deleteln()
Mit
deleteln()
wird die Zeile an der Stelle des Cursors gelöscht; alle folgenden Zeilen werden dabei automatisch um eine Zeile nach oben verschoben.
Möchte man an der gleichen Stelle am Bildschirm aufeinander folgende Textstellen
mit unterschiedlicher Länge ausgeben, so werden durch refresh();
nur die
jeweils neu darzustellenden Zeichen auf dem Bildschirm aktualisiert; wird
an der gleichen Startpositiion zunächst eine lange und danach eine kurze
Textstelle ausgegeben, so bleibt bei der Ausgabe der kurzen Textstelle ein Rest
der langen Textstelle bestehen.
Um den Bildschirm zu säubern, gibt es daher in Curses folgende Funktionen:
clrtoeol()
Mit
clrtoeol()
werden alle Zeichen von der Cursor-Position aus bis zum Ende der Zeile gelöscht („clear to end of line“).clrtobot()
Mit
clrtobot()
werden alle Zeilen von der Cursor-Position aus bis zum Ende des Fensters gelöscht („clear to bottom of window“).erase()
undclear()
Mit
erase()
undclear()
werden alle Zeichen auf dem gesamten Fenster gelöscht. Beide Funktionen sind nahezu identisch,clear()
ist allerdings etwas „gründlicher“ und bewirkt, dass das Fenster beim nächsten Aufruf vonrefresh()
komplett neu ausgegeben wird.
Attribute und Farben¶
Text kann in Curses auf den meisten Shells auch farbig oder fettgedruckt dargestellt werden. Eine solche Modifizierung wird mittels der folgenden Funktionen vorgenommen werden:
attron(attr)
Mit dieser Funktion wird das angegebene Attribut
attr
aktiviert.
attroff(attr)
Mit dieser Funktion wird das angegebene Attribut
attr
deaktiviert.
attrset(attr)
Mit dieser Funktion wird das angegebene Attribut
attr
aktiviert; alle sonstigen Attribute werden deaktiviert.
Die obigen Funktionen wirken sich auf die weitere Darstellung aller
Zeichenketten aus. Um den ausgegebenen Text wieder in „normaler“ Form
darzustellen, kann attrset(A_NORMAL)
verwendet werden. Eine Übersicht aller
Textattribute ist in der folgenden Tabelle zusammengestellt.
A_NORMAL |
Normaler Text |
A_BOLD |
Text in Fettschrift und mit erhöhter Helligkeit |
A_DIM |
Text mit verringerter Helligkeit (wird nicht von jeder Shell unterstützt) |
A_REVERSE |
Text mit vertauschter Vorder- und Hintergrundfarbe |
A_UNDERLINE |
Unterstrichener Text |
A_BLINK |
Blinkender Text (wird nicht von jeder Shell unterstützt) |
A_STANDOUT |
Hervorgehobener Text (entspricht meist A_REVERSE ) |
Um mehrere Attribute miteinander zu kombinieren, können diese entweder
nacheinander mittels attron()
aktiviert werden, oder in einer einzigen
attrset()
-Anweisung durch ein binäres Oder verbunden werden; beispielsweise
wird durch attrset(A_UNDERLINE | A_BOLD);
Text künftig unterstrichen und in
Fettdruck ausgegeben.
Farbiger Text
Um Text farbig auszugeben, sollte zunächst geprüft werden, ob eine farbige
Darstellung von der Shell unterstützt wird. Dazu gibt es in Curses die Funktion
has_colors()
, die entweder TRUE
oder FALSE
als Ergebnis liefert. Ist
farbiger Text auf der Shell möglich, so kann in Curses die Farbunterstützung
mittels der Funktion start_color()
freigeschaltet werden; dabei werden
zugleich die in der folgenden Tabelle angegebenen Farbnamen als symbolische
Konstanten definiert.
Nummer | Name | Farbe |
COLOR_BLACK |
Schwarz | |
COLOR_RED |
Rot | |
COLOR_GREEN |
Grün | |
COLOR_YELLOW |
Gelb | |
COLOR_BLUE |
Blau | |
COLOR_MAGENTA |
Magenta | |
COLOR_CYAN |
Cyan | |
COLOR_WHITE |
Weiss |
Aus diesen üblicherweise 8 Farben können mittels init_pair()
anschließend
so genannte „Farb-Paare“ definiert werden. In einem solchen Paar besteht aus
einer Farbnummer für den Vordergrund (der Schriftfarbe) und einer Farbnummer für
den Hintergrund, wobei anstelle der Nummern auch die oben aufgelisteten
symbolischen Konstanten verwendet werden können. Beispielsweise wird mit
init_pair(1, COLOR_YELLOW, COLOR_BLUE)
ein Farben-Paar mit der Nummer 1
definiert, bei dessen Verwendung Text in gelber Farbe auf blauem Hintergrund
ausgegeben wird.
Jedes so definierte Farbenpaar kann mittels attron()
beziehungsweise
attrset()
als Text-Attribut aktiviert werden:
if ( has_colors() == FALSE )
printw("Kein farbiger Text moeglich!");
else
start_color();
init_pair(1, COLOR_YELLOW, COLOR_BLUE );
attrset( COLOR_PAIR(1) );
printw("Farbiger Text, sofern moeglich!");
Neben der Angabe von COLOR_PAIR(n)
, die für das Farben-Paar mit der Nummer
steht, können ebenfalls weitere Attribute mittels eines binärem Oders
angegeben werden. Wird ein Farbenpaar mit dem Attribut A_BOLD
kombiniert, so
erscheint der Text nicht nur fettgedruckt, sondern auch in einer etwas helleren
Farbe; aus Schwarz wird als Vordergrundfarbe beispielsweise Grau. Bei einer
gezielten Verwendung kann damit das Farbspektrum etwas erweitert werden.
Es ist auch möglich dem Hintergrund ein Farben-Paar zuzuweisen; damit ändert
sich das Aussehen des Curses-Fensters, auch wenn kein Text ausgegeben wird. Die
Attribute für den Hintergrund werden mit der Funktion bkdg()
gesetzt. Wird
neben einem Farbenpaar und einem binärem Oder zusätzlich ein beliebiges Zeichen
angegeben, so wird der Hintergrund standardmäßig mit diesem Zeichen bedruckt:
bkgd( COLOR_PAIR(1) | '+' );
In diesem Fall würde mit den obigen Definitionen das Curses-Fenster blau
erscheinen und an allen Stellen ohne Text mit gelben +
-Zeichen aufgefüllt
werden.
Fenster und Unterfenster¶
In vielen interaktiven Programmen kann man zwischen verschiedenen Ansichtsfenstern wechseln, um beispielsweise eine Datei aus einem Filebrowser-Fenster auszuwählen oder eine Hilfe-Seite zu betrachten. Für eine bessere Übersichtlichkeit im Quellcode und eine bessere Effizienz ist es empfehlenswert, für jeden derartigen Zweck ein eigenes Fenster zu verwenden, das bei einem Wechsel nicht neu geschrieben, sondern nur wieder aktualisiert werden muss.
Ein neues Fenster wird mittels der Funktion newwin()
erstellt. Als
Rückgabewert liefert diese Funktion entweder einen Zeiger auf ein
WINDOW
-Objekt, oder NULL
, falls beim Erstellen des Fensters ein Fehler
aufgetreten ist. Als Argumente für newwin()
werden die Anzahl an Zeilen und
Spalten sowie die Startposition der oberen linken Ecke des Fensters angegeben:
int nrows = 5;
int ncols = 20;
int starty = 3;
int startx = 5;
mywin = newwin(nrows, ncols, starty, startx);
wrefresh(mywin);
Ein neues Fenster darf nicht größer sein als das Standard-Fenster stdscr
,
und muss mindestens eine Zeile und eine Spalte beinhalten. Gibt man allerdings
newwin(0,0,0,0);
ein, so wird ein neues Fenster erzeugt, das genauso groß
ist wie das Fenster stdscr
. Damit das neue Fenster auf dem Bildschirm
sichtbar wird, muss die Funktion wrefresh()
mit dem entsprechenden Namen des
Fensters aufgerufen werden. Bei Bedarf müssen zudem die Funktionen
keypad() und nodelay für das jeweilige
Fenster aufgerufen werden.
Die Funktionen move()
, addch
, addstr()
, printw()
, getch()
,
getstr()
lassen sich auf ein existierende Fenster werden, wenn an ihren
Funktionsname vorne ein w
angehängt und als erstes Argument ein Zeiger auf
das zu bearbeitende Fenster übergeben wird, also beispielsweise waddstr(mywin,
"Text")
.
Bei der Verwendung von mehreren sich überlappenden Fenstern ist nicht
sichergestellt, dass der Text von Curses wie erwartet dargestellt wird. Es wird
daher dringend empfohlen, entweder neue Fenster mit voller Fenstergröße zu
erzeugen, oder das Standard-Fenster nicht zu benutzen und dafür mehrere nicht
überlappende Fenster zu verwenden. Das Fenster, das zuletzt mit einem Aufruf
von wrefresh()
aktualisiert wurde, wird als „oberstes“ angezeigt und
verdeckt gegebenenfalls andere Fenster.
Um ein Fenster wieder zu schließen, wird die Funktion delwin()
verwendet,
wobei als Argument wiederum ein Zeiger auf ein Fenster übergeben wird, also
beispielsweise delwin(mywin)
. Das Fenster, das nach dem Löschen aktiv
angezeigt werden soll, muss dabei mittels wrefresh()
aktualisiert werden.
Gegebenenfalls muss es dazu erst mittels touchwin(win_name)
zur vollständigen
Aktualisierung vorgemerkt werden, falls ansonsten keine Änderungen vorgenommen
wurden.
Unterfenster erstellen
Neben Fenstern können in Curses auch so genannte Unterfenster erstellt werden. Diese können dazu verwendet werden, um einen Teil des Hauptfensters leichter ansteuern oder mit anderen Farb- und Textattributen versehen zu können. Der Inhalt eines Unterfensters hingegen stimmt mit dem Inhalt des Hauptfensters an der jeweiligen Stelle überein.
Ein neues Unterfenster kann, ebenso wie mit newwin() ein neues
Fenster erstellt wird, mittels subwin()
erzeugt werden, wobei als erstes
Argument der Name des übergeordneten Fensters und als weitere Argumente die
Anzahl an Zeilen und Spalten sowie die Startposition der oberen linken Ecke
angegeben werden:
// Neues Unterfenster erstellen:
my_subwin = subwin(mywin, nrows, ncols, starty, startx);
// Alternativ auch möglich:
my_subwin = derwin(mywin, nrows, ncols, starty, startx);
Die zweite Möglichkeit ein Unterfenster zu erstellen bietet die Funktion
derwin()
, wobei in diesem Fall die Werte starty
und startx
relativ
zum übergeordneten Fenster (und nicht relativ zum Hauptfenster stdscr
)
angegeben werden.
Alle Funktionen, die auf ein „richtiges“ Fenster angewendet werden können, lassen sich auch auf ein Unterfenster anwenden. Unterfenster haben einen eigenen Cursor und eigene Text- und Farbattribute; sie können selbst wiederum Ausgangspunkt für neue Unterfenster sein.
Mittels delwin(subwindow_name)
wird ein Unterfenster wieder geschlossen.
Bevor ein (Haupt-)Fenster geschlossen wird, sollten zuerst auf diese Weise alle
Unterfenster geschlossen werden, um Speicherlecks zu vermeiden (die Hauptfenster
haben keine Informationen darüber, ob sie Unterfenster beinhalten und können
diese somit nicht automatisch löschen). Der Inhalt des Subfensters, der dem
Inhalt des Hauptfensters entspricht, bleibt beim Löschen erhalten.[5]
Pads¶
Neben normalen Fenstern gibt es in Curses auch so genannte „Pads“. Während die Funktionen für Pads weitgehend mit den für normale Fenster identisch sind, ist ihre Größe nicht auf die Größe des Hauptfensters beschränkt; die maximale Größe eines Pads ist allerdings auf 32767 Zeilen beziehungsweise Spalten beschränkt.
Ein neues Pad wird folgendermaßen erzeugt:
int nrows = 1000;
int ncols = 1000;
WINDOW *mypad;
// Neues Pad erstellen:
mypad = newpad(nrows, ncols);
Mittels den für Fenster üblichen Ausgabefunktionen, beispielsweise
waddstr()
, kann Text auf einem Pad angezeigt werden. Damit die Änderungen
auf dem Bildschirm sichtbar werden, kann allerdings nicht wrefresh()
verwendet werden, da zusätzlich angegeben werden muss, von welcher Stelle aus
das Pad angezeigt werden soll: Üblicherweise ist ein Pad größer als der
Bildschirm, es kann somit nur ein Ausschnitt des Pads angezeigt werden. Dies
wird bei der Funktion prefresh()
berücksichtigt:
prefresh(padname, pad_ymin, pad_xmin, ymin, xmin, ymax, xmax);
Hierbei bezeichnen pad_ymin
und pad_xmin
die Koordinaten der oberen
linken Ecke innerhalb des Pads, von der aus der Inhalt angezeigt werden soll.
Die übrigen Argumente geben die Koordinaten des Bereichs an, in dem das Pad
relativ zum Hauptfenster angezeigt werden soll.
Subpads
Ebenso wie Fenster ein oder mehrere Unterfenster haben können, können Pads auch ein oder mehrere Subpads beinhalten. Ebenso wie bei den Unterfenstern ist der Inhalt eines Subpads mit dem Hauptpad identisch, das Subpad kann allerdings beispielsweise eigene Attribute und Farben aufweisen.
Ein neues Subpad kann mittels subpad()
erzeugt werden:[6]
int nrows = 1000;
int ncols = 1000;
int subrows = 50;
int subrows = 50;
WINDOW *mypad, *my_subpad;
// Neues Pad erstellen:
mypad = newpad(nrows, ncols);
// Neues Subpad erstellen:
// Allgemeine Syntax: subpad(nrows, ncols, starty, startx)
my_subpad = subpad(mypad, 0, 0, 10, 10);
Bei der Verwendung von Pads und Subpads ist zu beachten, dass diese nicht
innerhalb des Hauptfensters verschoben werden dürfen; die mvwin()
-Funktion
kann somit nicht auf Pads angewendet werden. Ebenso sind die
scroll()
-Funktionen für Pads nicht definiert.
Mittels delwin(padname)
kann ein (Unter-)Pad wieder gelöscht werden. Auch
hierbei sollten zunächst alle Subpads und erst zuletzt das Hauptpad gelöscht
werden, um Speicherlecks zu vermeiden.
Debugging von Curses-Programmen¶
Curses-Programme nutzen die Shell als Ein- und Ausgabefenster; sie lassen sich daher nicht innerhalb der gleichen Shell aufrufen und mit dem gdb-Debugger analysieren. Folgender Trick schafft hier Abhilfe:
Man öffnet ein zweites Shell-Fenster und gibt dort
tty
ein, um sich die Nummer dieser Shell anzeigen zu lassen; das Ergebnis lautet beispielsweise/dev/pts/23
. Anschließend gibt man in diesem Fenstersleep 1000000000000000000000
ein, um alle weiteren Eingaben an diese Shell für eine lange Zeit zu ignorieren. (Bei Bedarf kann der Schlafmodus mittelsStrg C
abgebrochen werden.)Im ersten Shell-Fenster kann man dann im Projektverzeichnis wie gewohnt
gdb programmname
eingeben, um den Debugger zu starten. Als erste Debugger-Anweisung wird dann der Eingabe-und-Ausgabe-Port des zu debuggenden Programms auf den Bezeichner des zweiten Shell-Fensters festgelegt:tty /dev/pts/23
Nun kann
run
eingeben werden, um das Programm im Debugger ablaufen zu lassen. Die Ausgabe des Programms erfolgt dabei im zweitem Shell-Fenster.
Anmerkungen:
[1] | Eine „Spalte“ in Curses der Breite eines Textzeichens; die meisten Fenster haben daher mehr Spalten als Zeilen. |
[2] | Für die Größe des Hauptfensters stdscr sind in Curses auch die
Makros LINES und COLS definiert, die vom Compiler durch die beim
Programmstart vorliegenden Werte ersetzt werden. |
[3] | Die Konstanten TRUE und OK beziehungsweise FALSE sind in der
Datei ncurses.h als 1 beziehungsweise 0 definiert. |
[4] | Mit nodelay(stdscr, FALSE) kann das ursprüngliche Verhalten von
getch() wieder hergestellt werden. |
[5] | Umgekehrt wird allerdings durch Funktionen wie wclear() der Inhalt
beim Löschen des Inhalts eines Fensters automatisch auch der Inhalt aller
Unterfenster gelöscht. |
[6] | Ein Pad kann ein Subpad, aber kein Unterfenster beinhalten. Man kann
innerhalb eines Pads also mittels subpad() ein Subpad erzeugen, jedoch
nicht mittels subwin() ein Unterfenster. |