Sehr Umfangreiche Webseite zum Programmieren in C Perl CGI, Skripting, Linux, Systemprogrammierung C C++ C/C++ ANSI C Linux Linuxsystemprogrammierung Semigrafik curses.h ncurses curses Linuxsystemprogrammieren Semigrafik curses.h ncurses curses 10. Semigrafik (curses.h)

10.4. Scrolling           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Damit überhaupt das Scrolling aktiviert wird, müssen Sie das Scrolling zuerst auch mit scrollok() aktivieren.

int scroll(WINDOW *win);

Mit der Funktion scroll() schieben Sie den, durch den Parameter win angegeben Bildschirm, um eine Zeile nach oben. Wenn stdscr angegeben wird, wird der ganze Bildschirm gescrollt.

int scrl(int anzahl);

Mit scrl() schieben Sie den Bildschirm mittels anzahl>0, anzahl Zeilen nach oben und mit anzahl<0, anzahl Zeilen nach unten. Mit der Funktion setscrreg() (siehe Kapitel zuvor) können Sie den Scrollbereich definieren.

Nun wollen wir ein etwas umfangreicheres Beispiel schreiben, wo die Funktionen scroll() und scrl() und andere schon kennen gelernte Funktionen vorkommen. Wir lassen ein kleines Raumschiff durch Sterne gleiten. Mit den Cursortasten Pfeil nach Rechts und Pfeil nach Links, können Sie das Raumschiff steuern. Mit q beenden Sie das Programm ...

#include <curses.h>
#include <stdlib.h>
/*'q'*/
#define QUIT 113
/* '<-'*/
#define LEFT 260
/* '->'*/
#define RIGHT 261


int main()
{
  int x=40,zufall, c,i;
  srand(79);
  initscr();
  keypad(stdscr,TRUE); /*Cursor und Funktionstasten*/
  noecho(); /*keine Ausgabe*/
  scrollok(stdscr,TRUE); /*Scrolling ein*/
  scroll(stdscr);

  while(c!=QUIT)
    {
      scrl(1);   /*Eine Zeile runter scrollen*/
      for(i=0;i<5;i++)
         {
           zufall=rand()%79;
           mvaddch(20,zufall,'*');
           mvprintw(0,0,"'q' drücken für Quit | Taste für Start | "
                        "<- nach links -> nach rechts");
          }

      c=getch();
      halfdelay(3);
      switch(c)
         {
          case LEFT : if(x<1) x=79;
                               else x--;
                               break;
         case RIGHT: if(x>79) x=1;
                               else x++;
                               break;
          default        : break;
         }

      mvdelch(9,x+2);mvdelch(9,x+1);mvdelch(9,x);
      mvdelch(9,x-1);mvdelch(9,x-2);
      mvaddch(10,x-1,ACS_LLCORNER);
      mvaddch(10,x+1,ACS_LRCORNER);
      mvaddch(10,x,ACS_TTEE);
     }
  endwin();
  return 0;
}

So siehts aus:

curses - Scollen

10.5. Attribute und Farben setzten           zurück Ein Kapitel tiefer Ein Kapitel höher zum Inhaltsverzeichnis

Jetzt wollen wir uns ansehen, wie wir einige Attribute setzen können. Folgende Funktionen stehen uns zur Verfügung ...

int attroff(int attribut);

Mit dieser Funktion wird ein Attribut das gesetzt war, deaktivieren. Beispielsweise ...

attroff(A_BLINK);

Damit wird das Blinken eines Textes oder Zeichens deaktiviert.

int attron(int attribut);
Die Funktion attron() ist das Gegenstück zur Funktion attroff() und dient zur Aktivierung eines Attributes. attron() eignet sich zum Beispiel für einen String der schon ein Attribut bekommen hat, um ein weiteres zu aktivieren.
int attrset(int attribut);

Mit attrset() setzten Sie jedes beliebige Attribut bzw. mehrere davib. z.B. ...

attrset(A_BOLD | A_BLINK);
printw("Dieser Text wird FETT und BLINKEND angezeigt");

Folgende Attribute können Sie verwenden:

Attribut Bedeutung
A_NORMAL  Normale Darstellung
A_STANDOUT   Zeichen stärkste Helligkeit
A_UNDERLINE  Zeichen unterstreichen
A_REVERSE      Invers
A_BLINK  blinken
A_DIM  Zeichen werden dunkler
A_BOLD    Fette Zeichen
A_PROTECT Geschützter Modus
A_INVIS    Unsichtbar
A_ALTCHARSET Umschalten auf Zeichengrafik
A_CHARTEXT  Macht aus dem 32Bit Wert (chtype) durch eine &-Verknüpfung einen 8Bit-Wert (ASCII)

Die Funktion COLOR_PAIR(n) setzt Farbenpaare zusammen (Hintergrund und Schrift)

Bevor Sie Farbe für ein Programm verwenden werden, müssen Sie erst mal testen, ob überhaupt Farben verfügbar sind ...

bool has_colors();

Dies schreiben Sie am besten folgendermaßen ...

if(has_colors==TRUE)
    /*Wir haben Farbe*/
else
    /*Wir haben keine Farbe*/

Ein weitere Abfrage zu den Farben, wäre die Funktion ...

bool can_change_colors(void);

Damit können Sie Abfragen, ob Sie die Farben vom Programm aus ändern können.

Falls Sie Farbe zur Verfügung haben (has_colors==TRUE), müssen Sie nach dem Aufruf von initscr() die Funktion ...

int start_color(void);

...aufrufen. Mit start_color() initialisieren Sie die Farben und gleichzeitig die globale Variablen COLORS und COLOR_PAIRS. COLOR_PAIRS stellt ein Farbenpaar da, aus Hintergrund und Schriftfarbe. Folgende Farben sind in der Headerdatei curses.h folgendermaßen definiert ...

#define COLOR_BLACK    0
#define COLOR_RED      1
#define COLOR_GREEN    2
#define COLOR_YELLOW   3
#define COLOR_BLUE     4
#define COLOR_MAGENTA  5
#define COLOR_CYAN     6
#define COLOR_WHITE    7
int init_pair(short paarnummer, int zeichen, int hintergrund);

Mit der Funktion init_pair() legen Sie eine Paarnummer fest, die Sie dann mit der Funktion attrset() ausgeben können. z.B. ...

init_pair(1,COLOR_RED,COLOR_GREEN);

Damit legen Sie ein Paar mit roter Schrift und grünem Hintergrund fest. Das Paar hat die Nummer 1. Dies setzten Sie jetzt wie folgt in der Praxis ein ...

attrset(COLOR_PAIR(1));
printfw("Dieser Text wird mit roten Zeichen auf grünen Hintergrund ausgegeben.");

...oder so ...

init_pair(2,COLOR_BLUE,COLOR_BLACK);
attrset(A_BOLD|COLOR_PAIR(2));
printw("Dieser Text wird mit fetter blauer Schrift "
       "und schwarzem Hintergrund ausgegeben.");

Mit init_pair() können Sie insgesamt 64 verschiedene Farbkombinationen festlegen. Nur das Farbpaar mit dem Index 0 (COLOR_PAIR(0)) kann nie geändert werden. Dieser Wert entspricht immer weissen Text auf schwarzem Hintergrund.

Um z.B. herauszufinden, welche Farbe in einem Farbpaar definiert wurde, gibt es die Funktion ...

int pair_content(short paarnummer, short *zeichenfarbe, short *hintergrundfarbe);

Wozu soll das gut sein? Es gibt eine Möglichkeiten alle Farbpaare auf einmal zu definieren...

int farbe1,farbe2,i=1;

if(has_color==TRUE)
   {
     start_color();
     for(farbe1=COLOR_WHITE;farbe1>=COLOR_BLACK;farbe1--)   //WHITE=7;BLACK=0
       for(farbe2=COLOR_BLACK; farbe2<=COLOR_WHITE; farbe2++)
         init_pair(i++,farbe1,farbe2);
   }

Damit werden alle 64 Farbenpaare auf einmal definiert. Um jetzt zu wissen, welchen Farbwert das Paar 50 hat, brauchen Sie nur ...

pair_content(50,&zeichenfarbe,&hintergrundfarbe);

...an die Adressen der Variablen zeichenfarbe und hintergrundfarbe übergeben.

Jetzt wollen wir die Attribute und Farben auf das Programm mit dem Raumschiff durchs Weltall loslassen ...

#include <curses.h>
#include <stdlib.h>
/* 'q' */
#define QUIT 113
/* '<-' */
#define LEFT 260
/* -> */
#define RIGHT 261

int main()
{
  int x=40,zufall, c,i,vor,hint;
  srand(79);
  initscr();
  if(has_colors()==TRUE)
     start_color();
  else
     exit (0);
  keypad(stdscr,TRUE);   /*Cursor und Funktionstasten*/

  noecho();   /*keine Ausgabe*/
  scrollok(stdscr,TRUE);   /*Scrolling ein*/
  scroll(stdscr);
  init_pair(1,COLOR_YELLOW,COLOR_BLACK);   /*Farbenpaar Nummer 1*/
  init_pair(2,COLOR_CYAN,COLOR_CYAN);      /*PaarNummer 2*/
  init_pair(3,COLOR_GREEN,COLOR_BLACK);    /*Farbenpaar Nummer 3*/
  init_pair(4,COLOR_BLACK,COLOR_GREEN);    /*Farbenpaar Nummer 4*/
  while(c!=QUIT)
   {
      scrl(1); /*Eine Zeile runter scrollen*/
      for(i=0;i<5;i++)
        {
          zufall=rand()%79;
          attrset(A_DIM|COLOR_PAIR(1));   /*Sterne dunkel ausgegeben*/
          mvaddch(20,zufall,'*');
          attrset(A_UNDERLINE|A_BOLD|COLOR_PAIR(4));   /*Blinkend*/
          mvprintw(0,0,"'q' drücken für Quit | Taste für Start | "
                       "<- nach links -> nach rechts");
        }

     c=getch();
     halfdelay(3);
     switch(c)
      {
        case LEFT : if(x<1) x=79;
                             else x--;
                             break;
       case RIGHT: if(x>79) x=1;
                             else x++;
                             break;
       default         : break;
     }

    mvdelch(9,x+2);mvdelch(9,x+1);mvdelch(9,x);
    mvdelch(9,x-1);mvdelch(9,x-2);
    attrset(A_BOLD|COLOR_PAIR(2)); /*Raumschiff fette Schrift*/
    mvaddch(10,x-1,ACS_LLCORNER);
    mvaddch(10,x+1,ACS_LRCORNER);
    attrset(A_BOLD|COLOR_PAIR(3));
    mvaddch(10,x,ACS_TTEE);
   }  /*Ende while()*/

  endwin();
  return 0;
}

So siehts aus:

curses - Farben und Attribute

10.6. Fensterroutinen           zurück Ein Kapitel tiefer zum Inhaltsverzeichnis

Jetzt wollen wir noch ein wenig die Fensterroutinen durchnehmen.

Fensterroutinen funktionieren genauso wie schon die im Kapitel zuvor besprochenen Funktionen, nur wird Ihnen noch ein Zeiger auf die WINDOW-Struktur übergeben. Zusätzlich bekommen die Funktionen, die sich auf das Fenster beziehen, noch das Präfix 'w' z.B. aus printw wird ...

wprintw(WINDOW *win, char *format, ...);

...oder aus mvprintw() wird...

mvwprintw(WINDOW *win, int y, int x, char *format, ...);

...u.s.w. Funktionen mit dem mv-Präfix, werden somit zu mvw-Präfixen. Einfach bei allen Funktionen die Sie kennen zusätzlich das w oder mvw und die WINDOW-Struktur übergeben. Falls Sie sich nicht sicher sind, schauen Sie sich einfach die entsprechende man-Pages dazu an. Zum Beispiel geben Sie 'man getch' ein und sie werden auch die Routine für wgetch für Fenster finden. Da alle bisher erlernten Funktionen somit genauso funktionieren, erspare ich mir die genauere Beschreibung dazu.

WINDOW *newwin(int anzahl_zeilen, int anzah_Spalten, int cursor_y, int cursor_X);

Mit newwin erstellen Sie ein neues Fenster mit anzahl_zeilen und anzahl_spalten. Dies machen Sie mit ...

stdscr=newline(anzahl_zeilen,anzahl_spalten,0,0)

int box(WINDOW *win, chtype zeichenvertikal, chtype zeichenhorizontal);

Mit der Funktion box() können Sie einen Rahmen um das Fenster win legen. z.B. ...

//Fenster mit dem Namen Fenster 10 Zeilen und 79 Spalten gross
fenster=newwin(10,79,0,0);
//Linien um den Fensterbereich ziehen eine Box
box(fenster,ACS_VLINE,ACS_HLINE);

Die ACS_ - Zeichen und den Datentyp chtype haben Sie ja bereits kennen gelernt.

Gleiches wie mit der Funktion box(), können Sie auch mit den folgenden Funktionen machen ...

int hline(chtype zeichen, int n);
int vline(chtype zeichen, int n);
WINDOW *dupwin(WINDOW *win);

Mit der Funktion dupwin() können Sie eine Kopie des WINDOW win machen. Beispielsweise ...

fenster2=dupwin(fenster1);

Wenn man dieses Fenster nicht mehr benötigt, so muss man dies mit der Funktion ...

int delwin(WINDOW *win);

...wieder freigeben. Beispiel ...

delwin(fenster2);

Wenn Sie ein Fenster verschieben wollen, machen sie dies mit dieser Funktion ...

int mvwin(WINDOW *win, int y, int x);

Als Ausgangspunkt wird die linke obere Ecke genommen. Diese ermitteln Sie, falls nicht bekannt, mit der Funktion ...

void getbegyx(WINDOW *win, int y, int x);

Achtung auch hier gilt, nicht den Adressoperator '&' für die Variablen y und x einzusetzen. Wollen Sie Beispielsweise den Bildschirm von der aktuellen Position drei Zeilen tiefer und zehn Spalten nach rechts setzten, dann macht man dies so ...

int y,x;
getbegyx(fenster1,y,x);
mvwin(fenster1,y+3,x+10);

Um die gesamte Größe eines Fensters zu ermitteln, gibt es die Funktion ...

int getmaxyx(WINDOW *win, int y, int x);

Auch hier benötigen Sie für die Variablen y und x keinen Adressoperator.

Manchmal wenn Sie die Funktion refresh() benötigen, um den gesamten Fensterinhalt neu zu zeichnen, benötigen Sie eine Funktion, die ein Fenster als verändert markiert. Denn, refresh() zeichnet nur dann neu, wenn sich auf dem Bildschirm auch etwas verändert hat. Dies können Sie mit dieser Funktion machen ...

int touchwin(WINDOW *win);

Den Standardbildschirm stdscr können Sie nun mittels refresh neu zeichnen. Bei anderen Fenstern benötigen Sie folgende Funktion ...

wrefresh(WINDOW *win);

Falls Sie überprüfen wollen, ob sich auf dem Fenster etwas verändert hat, können Sie dies mit der Funktion ...

int is_wintouched(WINDOW *win);

...abfragen. Zum Beispiel ...

if(is_wintouched(fenster1))   //wurde Fenster verändert
    wrefresh(fenster1);       //dann zeichne neu else   //ansonsten...
     {
       touchwin(fenster1);   //tu so wie wenn das Fenster verändert wurde
       wrefresh(fenster1);   //und zeichne dann neu
     }
int overwrite(const WINDOW *quelle, WINDOW *ziel);
int overlay(const WINDOW *quelle, WINDOW *ziel);

Diese beiden Funktionen kopieren (nur) die Zeichen vom Fenster quelle ins Fenster ziel. Der Unterschied der beiden Funktionen liegt daran, dass overlay() kein Leerzeichen mitkopiert.

Jetzt wollen wir noch ein Programm schreiben, dass die meisten der Fensterfunktionen selbsterklärend darstellen soll. Das Programm hält nach jedem kleinen Beispiel an. Bitte drücken sie eine Taste um zur nächsten Funktion im Programm zu springen. ...

#include <curses.h>
#define schwarz  0
#define rot      1
#define gruen    2
#define gelb     3
#define blau     4
#define lila     5
#define hblau    6
#define weiss    7


/*zeigt uns alle möglichen Farbpaare an*/

void show_all_pairs()
{
  int farbe1,farbe2,i=1,c;
  mvprintw(1,1,"Darstellung aller Farbenpaare : \n");
  if(has_colors()==TRUE)
   {
    start_color();
    for(farbe1=weiss; farbe1>=schwarz; farbe1--)
       for(farbe2=schwarz; farbe2<=weiss; farbe2++)
         {
           init_pair(i,farbe1,farbe2);
           attrset(COLOR_PAIR(i));
           printw(" %d ",i++);
         }
     }
  noecho();
  c=getch();
}


/*Erzeugen ein neues Fenster mit sämtlichen Attributen*/

WINDOW *create_new_window(WINDOW *neues_fenster, int zeilen, int spalten,
int hinterg, int vorderg, int begin_y, int begin_x, char *text,
int text_y, int text_x)
{
  neues_fenster=newwin(zeilen,spalten,begin_y,begin_x);
  init_pair(1,hinterg,vorderg);
  wattrset(neues_fenster,COLOR_PAIR(1));
  box(neues_fenster,ACS_VLINE,ACS_HLINE);
  mvwprintw(neues_fenster,text_y,text_x,text);
  return neues_fenster;
}


int main()
{
  WINDOW *fenster1,*fenster2,*fenster3;
  int y,x,max_y,max_x;
  initscr();
  raw();
  keypad(stdscr,TRUE);
  if(has_colors() == TRUE)
     start_color();
  show_all_pairs();
  clear();
  refresh();

  fenster1=create_new_window(fenster1,11,50,blau,weiss,0,0,"Hallo Welt",5,20);
  keypad(fenster1,TRUE);
  wrefresh(fenster1);
  wgetch(fenster1);

  fenster2=create_new_window(fenster2,10,50,rot,gruen,11,30,"Fenster 2",1,1);
  keypad(fenster2,TRUE);
  wrefresh(fenster2);
  wgetch(fenster2);

  mvwprintw(fenster1,5,5,"Wir verschieben Fenster 2 mit mvwin()");
  wrefresh(fenster1);
  wgetch(fenster1);

  getbegyx(fenster2,y,x);   /*Wo ist das Fenster 2 genau*/
  touchwin(stdscr);         /*stdscr neuzeichnen*/
  refresh();
/*Fenster 3 Zeilen tiefer und 20 Spalten nach links.*/
  mvwin(fenster2,y+3,x-20);
/*Da Fenster 1 nicht verändert wurde und wir neu zeichnen wollen*/
  touchwin(fenster1);
  wrefresh(fenster1);
  wrefresh(fenster2);
  wgetch(fenster2);

  mvwprintw(fenster1,5,5," Wir löschen Fenster 2 mit delwin() ");
  wrefresh(fenster1);
  wgetch(fenster1);

  delwin(fenster2); /*Löscht Fenster 2*/
  touchwin(stdscr);
  refresh();
  mvwin(fenster1,0,0);
  wrefresh(fenster1);
  wgetch(fenster1);

  mvwprintw(fenster1,5,5,"Wir kopieren dieses Fenster mit dupwin()");
  wrefresh(fenster1);
  wgetch(fenster1);

  fenster2=dupwin(fenster1);
  mvwin(fenster2,12,0);
  wrefresh(fenster2);
  wgetch(fenster2);

  mvwprintw(fenster1,5,1," Fenster 1 wird nun geloescht ");
  wrefresh(fenster1);
  wgetch(fenster1);

  delwin(fenster1);
  touchwin(stdscr);
  refresh();
  touchwin(fenster2);
  wrefresh(fenster2);
  wgetch(fenster2);

  attrset(COLOR_PAIR(0));
  mvprintw(1,1,"Nun wird das letzte Fenster auch noch beendet");
  refresh();
  wgetch(fenster2);
  delwin(fenster2);
  touchwin(stdscr);
  refresh();
  mvprintw(1,1,"Jetzt ist nur noch das Fenster stdscr in Betrieb!");
  getch();

  endwin();
  return 0;
}

Weiter mit 10.7. Mausprogrammierung mit ncurses