Ncurses: Fenster


<<< ncurses-Startseite ncurses << Inhaltsverzeichnis
< Spezialtasten Panels >


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 FensterBearbeiten

WINDOW *newwin(int nlines, int ncols, int begin_y, int begin_x);

BeispielBearbeiten

#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 FensterBearbeiten

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 subwinBearbeiten

#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.

FensterverzierungenBearbeiten

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.

RahmenBearbeiten

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 links
  • tr ... top right, Ecke oben-rechts

Wird 0 übergeben, so wird jeweils das in der Bibliothek festgelegte Standardzeichen verwendet.

LinienBearbeiten

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);

BeispielBearbeiten

#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öschenBearbeiten

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 refreshenBearbeiten

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:

  1. wnoutrefresh ... kopiert den gewünschten Fensterinhalt in den virtuellen Bildschirmspeicher.
  2. 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 UntouchBearbeiten

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);

BeispielBearbeiten

// ...
mvwaddstr(win, 4, 3, "Beenden -> F1 !"); 
wrefresh(win);
// ... 
  Die Zeichenkette wird wie erwartet in das Fenster eingefügt
// ...
mvwaddstr(win, 4, 3, "Beenden -> F1 !"); 
untouchwin(win);
wrefresh(win);
// ... 
  untouchwin - der nachfolgende Refresh bewirkt keine Änderung des ursprünglichen Fensterinhaltes
// ...
mvwaddstr(win, 4, 3, "Beenden -> F1 !"); 
untouchwin(win);
wrefresh(win);
touchwin(win);
wrefresh(win);
// ... 
  Durch Einfügung der touchwin-Anweisung wird dieses Fenster bei einem Refresh wieder aktualisiert


<<< ncurses-Startseite ncurses << Inhaltsverzeichnis
< Spezialtasten Panels >