Ncurses: Grundlegendes

Aus Wikibooks


<<< ncurses-Startseite ncurses << Inhaltsverzeichnis
< Einleitung Farben und andere Attribute >



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 dem bsp.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


<<< ncurses-Startseite ncurses << Inhaltsverzeichnis
< Einleitung Farben und andere Attribute >