3.5 Aufbau eines Programms

Programme für den PocketViewer sind immer prinzipiell gleich aufgebaut.
Nach der Initialisierung erfolgt meist der Bildschirmaufbau, die Definition von Bereich auf dem Touch-Screen, die auf den Stift reagieren sollen und eine Schleife, die jeden Stiftdruck aufnimmt und weiter bearbeitet.
Ein Beispielsourcecode ist hier abgedruckt:

/******************************************************************************
		Grundlagen der PocketViewer Programmierung
******************************************************************************/

#include  <stdrom.h>
#include  "define.h"
#include  "libc.h"
#include  "l_define.h"
#include  "l_libc.h"

#include  "grund.h"

/* Main-Pogramm */
void main()
{
  int loop=0;		/* Hauptschleife des gesamten Programms */
			/* allgemeine Initialisierung */	
  while (loop!=PV_ESC1)		/* Solange Programm nicht Beendet wird */
  {
    loop=screen1();		/* 1. Screen bearbeiten */
				/* Rückgabewert bestimmt weiteres Vorgehen  */
    switch(loop)
    {
      case PV_NEXT:		/* Rückgabewert für weiteren Screen */
        {
	  loop=screen2();	 /* Screen aufrufen */
	}
	break;
    }
  }
  LibJumpMenu(); 
}

/* Hier kommen die Definitionen der einzelnen Screens */
int screen1()
{
  int ret_code=0;		/* Unser Ergebnis dieses Screens */
  TCHSTS tsts;		/* Ergebnis der Touch-Abfrage */

  /* Bildschirmaufbau */	
  LibClrDisp();		/* Bildschirm löschen */
			/* Bildschirm füllen */
  LibPutDisp();		/*Bildschirm anzeigen */

  /* Touch-Felder definieren */
  LibTchStackClr();	/* Keine Touch-Felder von früher zulassen */
  LibTchStackPush(NULL);	/* Stack initialisieren */
  LibTchStackPush(TchHardIcon);	/* Icons für die Menüleiste */
  LibTchInit();
 
  /* Hauptschleife */
  while (ret_code==0)	/* Solange nichts gemacht wurde */
  {
    LibTchWait(&tsts);	/* Auf Touch warten */
    switch(tsts.obj)	/* Auswerten des Touch */
    {
      case OBJ_HIC_ESC:	/* ESC_Taste gedrückt */
      {
        ret_code=PV_ESC1;	/* Screen1 beenden */
      }
      break;		
				/* Weitere Dinge tun */
    }
  }
  return(ret_code);			/* Ergebnis melden */
}


int screen2()
{
  int ret_code=0;		/* Unser Ergebnis dieses Screens */
  TCHSTS tsts;		/* Ergebnis der Touch-Abfrage */

  /* Bildschirmaufbau */	
  LibClrDisp();		/* Bildschirm löschen */
			/* Bildschirm füllen */
  LibPutDisp();		/*Bildschirm anzeigen */

  /* Touch-Felder definieren */
  LibTchStackClr();	/* Keine Touch-Felder von früher zulassen */
  LibTchStackPush(NULL);	/* Stack initialisieren */
  LibTchStackPush(TchHardIcon);	/* Icons für die Menüleiste */

	/* Hauptschleife */
  while (ret_code==0)	/* Solange nichts gemacht wurde */
  {
    LibTchWait(&tsts);	/* Auf Touch warten */
    switch(tsts.obj)	/* Auswerten des Touch */
    {
      case OBJ_HIC_ESC:	/* ESC_Taste gedrückt */
      {
        ret_code=PV_ESC2;	/* Screen2 beenden */
      }
      break;		
				/* Weitere Dinge tun */
    }
  }
  return(ret_code);			/* Ergebnis melden */
}

Dieses Programm ist in sich bereits lauffähig, macht allerdings noch nichts.
Zur Beschreibung des Ablaufs:

  1. Jedes Programm beginnt damit, die benötigten include-Files zu laden.
  2. Die main()-Routine besteht hier aus einer Schleife, die nach einer Initialisierung jeden Screen aufruft und abhängig vom Ergebnis dieses Screens auf weitere Screens verzweigt. Hier sollte man darauf achten, dass jeder Screen in einer eigenen Routine arbeitet und andere Screens nur von der main() aufgerufen werden. Über den Rückgabewert eines Screens kann man steuern, welche Screens aufgerufen werden sollen. Es ist zwar auch möglich, aus einem Screen heraus, direkt weitere Screens aufzurufen, allerdings setzt sich jeder Screen seine eigenen Inhalte und Touch-Felder, so dass diese nach der Rückkehr wieder neu gesetzt werden müssten, was am Anfang einer Screen-Routine sowieso schon passiert.
  3. Nach dem Aufruf eines Screens gibt dieser einen Rückgabewert, der in einer Abfrage verwendet wird, um weitere Screens aufzurufen.
  4. Ein Rückgabewert sollte reserviert sein, um das Programm zu beenden. Prinzipiell kann das Programm durch Antippen eines Menüeintrags immer beendet werden, aber ein sauberer Programmabschluss sollte vorgesehen sein.
  5. Über LibJumpMenu() wird ein Programm so beendet, dass das Hauptmenü des PocketViewers wieder angezeigt wird. Wenn dieser Befehl fehlt, dann kehrt das Programm niemals zum PVOS zurück und der PocketViewer hängt sich auf.
Die Routinen, um die einzelnen Screens zu behandeln, sind ebenfalls immer ähnlich aufgebaut:
  1. Jeder Screen sollte einen Rückgabewert liefern, damit die Hauptschleife weiss, was als nächstes zu tun ist.
  2. In der Variablen tsts wird gespeichert, welche Position auf dem Bildschirm angetippt wurde.
  3. Ein Bildschirm sollte mit LibClrDisp() erstmal leer gemacht werden, um den Bildschirmaufbau sauber durcführen zu können.
  4. Der Touch-Stack sollte auf jedem Bildschirm geleert und neu aufgebaut werden. Dadurch bleiben keine Bereiche von früheren Screens übrig, die auf den Touch reagieren und evtl. ein falsches Ergebnis liefern.
  5. Ein gutes Programm sollte die HardIcons am unteren Bildschirm mit berücksichtigen, um einen jederzeitigen Wechsel auf eine dieser Anwendungen zu ermöglichen. Allerdings bewirkt ein solcher Wechsel ein sofortiges Ende des Programms, ohne dass das Programm darüber informiert wird. Es können also auch keine Daten mehr gesichert werden oder dergleichen. Möchte man nicht, dass das Programm jederzeit beendet wird, so sollte man die HardIcons nicht in den Touch-Stack aufnehmen.
  6. In einer Schleife wird jetzt darauf gewartet, dass der Benutzer eine Stelle auf dem Bildschirm antippt.
  7. Über eine switch()-Anweisung kann dieser Touch ausgewertet werden und weitere Aktionen laufen.
  8. In diesem Beispiel wird nur die ESC-Taste abgeprüft, um die Screen-Routine zu beenden.

Damit wäre der prinzipielle Programmaufbau schon erledigt.
Dieses Programm ist so bereits lauffähig, sofern man in dem include-File grund.h die Defines und Funktionsprototypen gesetzt hat.
An den entsprechenden Stellen im Sourcecode können nun eigene Funktionalitäten eingsetzt werden.
Übrigens wird die Routine screen2() niemals angesprungen, weil screen1() keine Möglichkeit vorsieht, hierhin zu verzweigen. Die Routine steht nur dabei, um in main() diese Verzweigung zu veranschaulichen.

Für Ergänzungen wenden Sie sich bitte an: Jürgen Wagner