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.8. Videoverwaltungsprogramm mit ncurses           zurück zum Inhaltsverzeichnis

Für die Praxis habe ich mir als Beispiel schon vor längerer Zeit ein Videoverwaltungsprogramm zusammengebastelt, welches als Anschauungsbeispiel ganz gut geeignet sein dürfte.

So siehts aus:



Ich habe den Quellcode in zwei Teile aufgeteilt. In dem einen Teil findet die Datenverarbeitung des Programms statt und in dem anderen Teil die Ausgabe mit curses auf dem Bildschirm.

Zuerst aber noch die Headerdatei struc.h mit einer kurzen Erklärung zu den einzelnen Funktionen ...

/*struc.h*/
#ifndef _STRUC
#define _STRUC
#include <unistd.h>
#include <curses.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

#define DAT "video.dat"

typedef struct  film{
                  char genere[75];
                  char titel[75];
                  char regie[75];
                  char darsteller[75];
                  char fsk[3];
                  char jahr[5];
                  struct film *next;
                  struct film *previous;
                }ARCHIV;

ARCHIV *anfang,*next,*ende;

enum{ERROR=0, SUCCESS};

void start();    /*anfang,ende und next den NULL-Zeiger übergeben*/
/*Sortieren nach Filmtitel */
void sortieren(char *, char *, char *, char *, char *, char *);
/*Element sortiert eingeben*/
void einhaengen(char *, char *, char *, char *, char *, char *);
int comp(ARCHIV*, ARCHIV *);  /*Vergleichsfunktion*/
void loesche(char *);    /*Funktion zum löschen eines Filmes "titel" aus dem ARCHIV*/
ARCHIV *searching(char *);  /*Funktion zum suchen eines Filmes im Archiv*/
int loading(FILE *);             /*Laden des Archives beim Programmstart*/
int open_for_read(FILE **);  /*Datei video.dat zum lesen öffnen*/
int create_new_file(FILE **);  /*Falls video.dat nicht existiert wird sie neu erstellt*/
void save_file(FILE *);        /*Archiv speichern in "video.dat"*/
int file_open_for_write(FILE **); /*Archiv zum Beschreiben öffnen*/


void show_archiv(void);        /*Zeigt das Menü für Archiv*/
void show_work_archiv(void);  /*zeigt Menü zum Bearbeiten des Archives an*/
void show_search_scroll(void);  /*Zeigt das Suchmenü zum scrollen an*/
/*Suchmaske mit Flag womit wir die Funktion zum Ändern(1) und suchen(0) benutzen*/
void search_mask(int );
void new_title(void);            /*Eingabemaske eines neuen Filmtitels*/
void fehler_curses(char *);      /*Popup-Fenster zur Fehlerausgabe*/
void output(ARCHIV *);           /*Ausgabe eines bestimmten Filmes*/
void delete_title(void);         /*Funktion zum löschen eines Filmes aus der Liste*/

#endif

Als nächstes nun der Code für die Darstellung des Programms mittels curses und Gleichzeitig unser Hauptprogramm ...

/*video.c*/
#include "struc.h"

void show_archiv(void)
{
 int press;

 do{
       clear();
       attrset(A_BOLD|COLOR_PAIR(1));
       mvprintw(11,21," -1- Nach Film suchen mit Suchbegriff \n");
       mvprintw(12,21," -2- Liste durchscrollen              \n");
       mvprintw(13,21," -3- Zurück                           \n");
       refresh();
       switch(press=mvgetch(0,0))
        {
          case '1':  attrset(COLOR_PAIR(3));
                         mvprintw(11,21," -1- Nach Film suchen mit Suchbegriff \n");
                         refresh(); usleep(400000);
                         search_mask(0);
                         break;
          case '2':  attrset(COLOR_PAIR(3));
                         mvprintw(12,21," -2- Liste durchscrollen              \n");
                         refresh(); usleep(400000);
                         show_search_scroll();
                         break;
          case '3':  attrset(COLOR_PAIR(3));
                         mvprintw(13,21," -3- Zurück                           \n");
                         refresh(); usleep(400000);
                         return;
          default :  break;
        }
       }while(press!=3);
 }

void show_work_archiv(void)
{
  int press;

 do{
       clear();
       attrset(A_BOLD|COLOR_PAIR(1));
       mvprintw(11,28," -1- Ändern                 \n");
       mvprintw(12,28," -2- Neuen Titel hinzufügen \n");
       mvprintw(13,28," -3- Titel löschen          \n");
       mvprintw(14,28," -4- Zurück                 \n");
       refresh();
       switch(press=mvgetch(0,0))
        {
          case '1':  attrset(COLOR_PAIR(3));
                         mvprintw(11,28," -1- Ändern                 \n");
                         refresh(); usleep(400000);
                         search_mask(1);
                         break;
          case '2':  attrset(COLOR_PAIR(3));
                         mvprintw(12,28," -2- Neuen Titel hinzufügen \n");
                         refresh(); usleep(400000);
                         new_title();
                         break;
          case '3':  attrset(COLOR_PAIR(3));
                         mvprintw(13,28," -3- Titel löschen          \n");
                         refresh(); usleep(400000);
                         delete_title();
                         break;
          case '4':  attrset(COLOR_PAIR(3));
                         mvprintw(14,28," -4- Zurück                 \n");
                         refresh(); usleep(400000);
                         return;
          default :  break;
        }
       }while(press!=4);
 }


void show_search_scroll(void)
{
  WINDOW *neu,*neu2;
  ARCHIV *archiv;
  int i=1, j, press;
   attrset(COLOR_PAIR(4));
  neu=newwin(7, 72, 0, 0);  //Neues Fenster mit 5 Zeilen 70 Spalten
  neu2=newwin(5, 70, 0,0);
  keypad(neu2, TRUE);
  mvwprintw(stdscr, 1,  14, "Scrollen mit 'Pfeil nach oben' und 'Pfeil nach unten'");
  mvwprintw(stdscr, 2,  10, "Auswählen mit 'Pfeil nach rechts' und Abbrechen mit 'Escape'");
  wrefresh(stdscr);
   wattrset(neu, COLOR_PAIR(2));
  box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
  mvwin(neu, 3,5); //Fenster an die richtige Position
  mvwin(neu2,4,6);
  wrefresh(neu);  //Fenster zeichnen
  wrefresh(neu2);
  if(anfang == NULL)
    {
      fehler_curses("            Es sind keine Filme in der Liste vorhanden!!!!!!!!!  ");
      return;
    }
  archiv=anfang;
  noecho();
  do{
        wclear(neu2);

        box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
        wrefresh(neu);

        wattrset(neu2, COLOR_PAIR(3));
        mvwprintw(neu2, 1,1, "%s",archiv->titel);
        wattrset(neu2, COLOR_PAIR(0));
        if(archiv->next != NULL)
            {
              wmove(neu2, 2, 1);
              insertln();
              mvwprintw(neu2, 2, 1, "%s",archiv->next->titel);
              if(archiv->next->next != NULL)
                {
                 wmove(neu2, 3,1);
                 insertln();
                 mvwprintw(neu2, 3,1, "%s",archiv->next->next->titel);
                }
            }
        wrefresh(neu2);
        switch(press=wgetch(neu2) )
         {
           case KEY_DOWN :  if(archiv->next != NULL)
                                              archiv=archiv->next;
                                           break;
           case KEY_UP       :  if(archiv->previous != NULL)
                                             archiv=archiv->previous;
                                           break;
           case KEY_RIGHT  : output(archiv);
                                           break;
           default                  : break;
         }
       }while(press != 27);
 }


void search_mask(int flag)
{
 WINDOW *neu;
 char film[75],input[75];
 ARCHIV *found;
 int i=1,press;

 neu=newwin(8,76,0,0);
 keypad(neu, TRUE);
 wattrset(neu, COLOR_PAIR(2));
 box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
 mvwin(neu, 2,2); //Fenster an die richtige Position

 wattrset(neu, COLOR_PAIR(4));
 mvwprintw(neu, 3,3,"Filmtitel       :  ");
 wrefresh(neu);
 echo();
 wgetnstr(neu, film, 75);
 noecho();

 if((found=searching(film)) == NULL)
  {
   fehler_curses("                          Suche erfolglos!!!                     ");
   return;
  }
 else
   {
     wclear(neu);
     wattrset(neu, COLOR_PAIR(5));
     box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
     wattrset(neu, COLOR_PAIR(0));
     mvwprintw(neu, 1,3,"Genere       :  %s",found->genere);
     mvwprintw(neu, 2,3,"Titel        :  %s",found->titel);
     mvwprintw(neu, 3,3,"Regie        :  %s",found->regie);
     mvwprintw(neu, 4,3,"Schauspieler :  %s",found->darsteller);
     mvwprintw(neu, 5,3,"FSK          :  %s",found->fsk);
     mvwprintw(neu, 6,3,"Jahr         :  %s",found->jahr);
     wrefresh(neu);
     if(flag==0)
        wgetch(neu);
   }
 if(flag==1)
  {
   do{
          if(i==0)
             i=6;
          else if(i==7)
            i=1;
          mvwprintw(stdscr, 0,  14, "Scrollen mit 'Pfeil nach oben' und 'Pfeil nach unten'");
          mvwprintw(stdscr, 1,  10, "Ändern mit 'Pfeil nach rechts'  und Abbrechen mit 'Escape'");
          wrefresh(stdscr);
           wattrset(neu, COLOR_PAIR(5));
          box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
           wattrset(neu, COLOR_PAIR(0));
          wmove(neu ,i,19);
          wrefresh(neu);
          switch(press=wgetch(neu))
            {
              case KEY_DOWN  :     i++;
                                                  break;
              case KEY_UP         :    i--;
                                                  break;
              case KEY_RIGHT   :  wclrtoeol(neu);
                                                 wrefresh(neu);
                                                 echo();
                                                 wgetnstr(neu, input, 75);
                                                 noecho();
                                                 if(i==1)  strcpy(found->genere, input);
                                                 if(i==2)  strcpy(found->titel, input);
                                                 if(i==3)  strcpy(found->regie, input);
                                                 if(i==4)  strcpy(found->darsteller, input);
                                                 if(i==5)  strcpy(found->fsk, input);
                                                 if(i==6)  strcpy(found->jahr, input);
                                                 input[0]='\0';
                                                 break;
              default                    :   break;
           }
      }while(press != 27);
   }
}


void new_title(void)
{
 WINDOW *neu;
 char genere[75],titel[75],regie[75],darsteller[75],fsk[3],jahr[5];

 neu=newwin(8,76,0,0);
 keypad(neu, TRUE);
 wattrset(neu,COLOR_PAIR(5));
 box(neu, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
 wattrset(neu,COLOR_PAIR(0));
 mvwin(neu, 1,2); //Fenster an die richtige Position
 mvwprintw(neu, 1,3,"Genere       :  ");
 mvwprintw(neu, 2,3,"Titel        :  ");
 mvwprintw(neu, 3,3,"Regie        :  ");
 mvwprintw(neu, 4,3,"Schauspieler : ");
 mvwprintw(neu, 5,3,"FSK          : ");
 mvwprintw(neu, 6,3,"Jahr         : ");
 wrefresh(neu);
 echo();
 mvwgetnstr(neu, 1,18, genere, 75);
 mvwgetnstr(neu, 2,18, titel, 75);
 mvwgetnstr(neu, 3,18, regie, 75);
 mvwgetnstr(neu, 4,18, darsteller, 75);
 mvwgetnstr(neu, 5,18, fsk, 3);
 mvwgetnstr(neu, 6,18, jahr, 5);
 noecho();

 sortieren(genere,titel,regie,darsteller,fsk,jahr);
}


void fehler_curses(char *message)
{
 WINDOW *pop;

 pop=newwin(3,75,0,0);
 wattrset(pop, COLOR_PAIR(1));
 box(pop, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
 mvwin(pop, 20,2); //Fenster an die richtige Position
 mvwprintw(pop, 1,1,"    %s   ",message);
 wrefresh(pop) ;
 wgetch(pop);
 wclear(pop);
 wrefresh(pop);
}


void output(ARCHIV *movie)
{
 WINDOW *output;

 output=newwin(8,76,0,0);
 wattrset(output, COLOR_PAIR(5));
 box(output, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
 keypad(output,TRUE);

   if(movie == NULL)
    {
      fehler_curses("            Es sind keine Filme in der Liste vorhanden!!!!!!!!!  ");
      return;
    }

  mvwin(output, 15,2); //Fenster an die richtige Position
  wattrset(output, COLOR_PAIR(0));
  mvwprintw(output, 1,3,"Genere       :  ");
  mvwprintw(output, 2,3,"Titel        :  ");
  mvwprintw(output, 3,3,"Regie        :  ");
  mvwprintw(output, 4,3,"Schauspieler : ");
  mvwprintw(output, 5,3,"FSK          : ");
  mvwprintw(output, 6,3,"Jahr         : ");

  mvwprintw(output, 1,18,"%s",movie->genere);
  mvwprintw(output, 2,18, "%s",movie->titel);
  mvwprintw(output, 3,18, "%s",movie->regie);
  mvwprintw(output, 4,18, "%s",movie->darsteller);
  mvwprintw(output, 5,18,"%s",movie->fsk);
  mvwprintw(output, 6,18, "%s",movie->jahr);
  wrefresh(output);
  wgetch(output);
  wclear(output);
  wrefresh(output);
}


void delete_title()
{
 WINDOW *delete;
 char search[75];

 delete=newwin(5, 76, 0, 0);
 wattrset(delete, COLOR_PAIR(5));
 box(delete, ACS_VLINE, ACS_HLINE); //Linien um das neue Fenster
 wattrset(delete, COLOR_PAIR(0));
 mvwin(delete, 2, 3);

 mvwprintw(delete, 2,2, "Welchen Film wollen sie  entfernen :   ");
 wrefresh(delete);
 echo();
 wgetnstr(delete, search, 75);
 noecho();

 loesche(search);
}




int main(int argc, char **argv)
{
 int press;
 FILE *file;

 initscr();        //Curses initialisieren

 start_color();   //Farben initialisieren
 if(has_colors () == TRUE)  //Können wir Farben benutzen
  {
   init_pair(1, COLOR_WHITE, COLOR_RED); //Weiss-Rot
   init_pair(2, COLOR_RED, COLOR_RED);  //Schwarz-Rot
   init_pair(3, COLOR_RED, COLOR_WHITE);    //Rot-Weiss
   init_pair(4, COLOR_RED,COLOR_BLACK);
   init_pair(5, COLOR_BLUE, COLOR_BLUE);
  }

 cbreak();       //nur noch STRG + S, ...+Q, ...+C werden beachtet
 noecho();       //keine Ausgabe auf dem Bildschirm
 keypad(stdscr,TRUE);  //Funk.-u.-Cursortasten als Taste behandeln

  if((loading(file)) == SUCCESS);
 else if((create_new_file(&file)) == SUCCESS)
  {
    start();
    fehler_curses("                 \"video.dat\" neu erstellt!!!                      ");
    fclose(file);
  }

 do{
        clear();
        attrset(A_BOLD|COLOR_PAIR(1));
        mvprintw(11,30," -1- Zum Filmarchiv   \n");
        mvprintw(12,30," -2- Filme verwalten  \n");
        mvprintw(13,30," -3- Programm beenden \n");
        refresh();

        switch(press=mvgetch(0,0))
         {
          case '1':  attrset(COLOR_PAIR(3));
                         mvprintw(11,30," -1- Zum Filmarchiv   \n");
                         refresh(); usleep(400000);
                         show_archiv();
                         break;
          case '2':  attrset(COLOR_PAIR(3));
                         mvprintw(12,30," -2- Filme verwalten  \n");
                         refresh(); usleep(400000);
                         show_work_archiv();
                         break;
          case '3':  attrset(COLOR_PAIR(3));
                         mvprintw(13,30," -3- Programm beenden \n");
                         refresh(); sleep(1);
                         save_file(file);
                         echo();endwin();exit(0);
          default: break;
         }
         fflush(stdin);
         refresh();
        }while(press!=3);

 endwin();   //Curses beenden
 return 0;
}

Jetzt noch der Quellcode zur Verarbeitung der Daten des Programms ...

/*structur.c*/
#include "struc.h"

/*Startadressen für die Zeiger next,anfang und ende*/
void start(void)
{
 next=anfang=ende=NULL;
}

void sortieren(char gen[],char tit[],char reg[],char dar[],char f[],char j[])
{
 ARCHIV *zeiger1, *zeiger2, *zeiger3;

 if((zeiger2=(ARCHIV *)malloc(sizeof(ARCHIV))) == NULL)
  {
   fehler_curses("Ich konnte keinen Speicher reservieren....versuchen sie es erneut!");
   return;
  }
 strcpy(zeiger2->genere, gen);
 strcpy(zeiger2->titel, tit);
 strcpy(zeiger2->regie, reg);
 strcpy(zeiger2->darsteller, dar);
 strcpy(zeiger2->fsk, f);
 strcpy(zeiger2->jahr, j);

 /*1.Element ? */
 if(anfang==NULL)
   {
    if((anfang=(ARCHIV *)malloc(sizeof(ARCHIV))) == NULL)
    {
     fehler_curses("Ich konnte keinen Speicher reservieren....versuchen sie es erneut!");
     return;
   }
     strcpy(anfang->genere, gen);
     strcpy(anfang->titel, tit);
     strcpy(anfang->regie, reg);
     strcpy(anfang->darsteller, dar);
     strcpy(anfang->fsk, f);
     strcpy(anfang->jahr, j);

    anfang->next=NULL;
    ende=anfang;
    ende->previous=NULL;
    }
 else
  {
    zeiger1=anfang;

    while((zeiger1->next != NULL )  && (comp(zeiger1, zeiger2) < 0))
       zeiger1=zeiger1->next;

    if(zeiger1->next == NULL)   //hinten anhängen
     {
      if((zeiger1->next=(ARCHIV *) malloc(sizeof(ARCHIV))) == NULL)
       {
        fehler_curses("Ich konnte keinen Speicher reservieren....versuchen sie es erneut!");
        return;
       }
      zeiger3=zeiger1;
      zeiger1=zeiger1->next;

      strcpy(zeiger1->genere, gen);
      strcpy(zeiger1->titel, tit);
      strcpy(zeiger1->regie, reg);
      strcpy(zeiger1->darsteller, dar);
      strcpy(zeiger1->fsk, f);
      strcpy(zeiger1->jahr, j);

      zeiger1->next=NULL;
      ende=zeiger1;
      zeiger1->previous=zeiger3;
     }
    else if(zeiger1==anfang && (comp(zeiger1, zeiger2)>=0)) //vorne anhängen
     {
      if((anfang=(ARCHIV *)malloc(sizeof(ARCHIV))) == NULL)
        {
         fehler_curses("Ich konnte keinen Speicher reservieren....versuchen sie es erneut!");
         return;
        }
     strcpy(anfang->genere, gen);
     strcpy(anfang->titel, tit);
     strcpy(anfang->regie, reg);
     strcpy(anfang->darsteller, dar);
     strcpy(anfang->fsk, f);
     strcpy(anfang->jahr, j);
     anfang->next=zeiger1;
       anfang->previous=NULL;
       zeiger1->previous=anfang;
     }
    else if(comp(zeiger1, zeiger2) >=0) //mittendrin
     {
      zeiger3=anfang;
      while(zeiger3->next != zeiger1)
         zeiger3=zeiger3->next;

      zeiger2->previous=zeiger3;
      zeiger2->next=zeiger1;
      zeiger1->previous=zeiger2;
      zeiger3->next=zeiger2;
      }
    else
     //Fehler-Routine für curses schreiben
       exit(0);
  }
}

/*Vergleichsfunktion*/
int comp(ARCHIV *arch, ARCHIV *neu)
{
  int ret=strcmp(arch->titel,neu->titel);
  return ret;
}


/*Löschen eines Filmes aus der Liste*/
void loesche(char wen[])
{
 ARCHIV *zeiger ,*zeiger1, *zeiger2;
 int found=0;
/*Ist überhaupt ein Element vorhanden?*/
 if(anfang != NULL)
 {
  /*Ist unser 1.Element das von uns gesuchte (wen[]) ?*/
  if(strcmp(anfang->titel,wen) == 0)
   {
     zeiger=anfang->next;
      if(zeiger == NULL)
        {
          free(anfang);
          anfang=NULL;
          ende=NULL;
          return;
        }
       zeiger->previous=NULL;
       free(anfang);
       anfang=zeiger;
       return;
   }
  /*Ist das letzte Element das von uns gesuchte ? */
  else if(strcmp(ende->titel,wen) == 0)
   {
     zeiger=ende->previous;
     zeiger->next=NULL;
     zeiger1=ende;
     ende=zeiger;
     free(zeiger1);
     return;
   }
  else
   {
   /*Es ist nicht das 1.Element zu löschen. Wir suchen in
        der weiteren Kette ob das zu löschende Element vor-
        handen ist*/
    zeiger=anfang;
    while(zeiger->next != NULL)
      {
        zeiger1=zeiger->next;
        /*Ist die Adresse von zeiger1 der gesuchte Namen?*/
        if(strcmp(zeiger1->titel,wen) == 0)
          {
            /*Falls ja dann.....*/
             zeiger->next=zeiger1->next;
             zeiger2=zeiger1->next;
             zeiger2->previous=zeiger;
             free(zeiger1);
             return;
          }
        zeiger=zeiger1;
       }//Ende while
    }//Ende else
  }//Ende if(anfang != NULL)
 fehler_curses("         Ich kann den Film  nicht im Archiv finden ?!?!?!         ");
}



ARCHIV *searching(char film[])
{
 ARCHIV *zeiger;

 if(anfang == NULL)
  {
   fehler_curses("            Es befinden sich keine Filme in der Liste                ");
   return NULL;
  }

 zeiger=anfang;
 while((zeiger != NULL)  &&  (strcmp(zeiger->titel, film) != 0))
   zeiger=zeiger->next;

 return zeiger; //Entweder NULL oder den gefundenen Film
}


int loading(FILE *file)
{
 ARCHIV zeiger;

 if(open_for_read(&file))
  {
     while(fread(&zeiger,sizeof(ARCHIV),1,file))
        sortieren(zeiger.genere, zeiger.titel, zeiger.regie,
        zeiger.darsteller, zeiger.fsk, zeiger.jahr);
      return SUCCESS;
  }
 return ERROR;
}


int open_for_read(FILE **file)
{
 if((*file = fopen(DAT ,"r")) == NULL)
  {
     fehler_curses("          Konnte \"video.dat\" nicht zum lesen oeffnen!             ");
     return ERROR;
  }
  return SUCCESS;
}


int create_new_file(FILE **file)
{
 if((*file = fopen(DAT ,"w+")) == NULL)
  {
    fehler_curses("            Konnte \"video.dat\" nicht zum nicht erzeugen !                 ");
    return ERROR;
  }
 return SUCCESS;
}


void save_file(FILE *file)
{
 ARCHIV *zeiger;

 /*Im "w+" - Modus oeffnen*/
 if(file_open_for_write(&file))
 {
  zeiger=anfang;
  while(zeiger != NULL)
  {
     fwrite(zeiger,sizeof(ARCHIV),1,file);
     zeiger=zeiger->next;
  }
 }
 fclose(file);
}


int file_open_for_write(FILE **file)
{
 if((*file = fopen(DAT, "w+")) == NULL)
  {
   fehler_curses("        Konnte \"video.dat\" nicht zum schreiben oeffnen!           ");
   return ERROR;
  }
 return SUCCESS;
}

bersetzten müssen sie diese drei Codeteile mit ...

gcc -o video video.c structur.c -lncurses

Weiter mit 11. Mausprogrammierung mit gpm.h