Das folgende Beispielprogramm nutzt nur das Setzen von Farben und Punkten:
/* Example canvas.c */ int do_work=0; int frame,menubar; int file,calc; int quit,start,stop; int canvas,obj; if(j_start()<0) printf("can't connect to JAPI server\n"),exit(0); frame = j_frame(NULL); j_setsize(frame,290,330); menubar = j_menubar(frame); file = j_menu(menubar,"File"); calc = j_menu(menubar,"Calc"); quit = j_menuitem(file,"Quit"); start = j_menuitem(calc,"Start"); stop = j_menuitem(calc,"Stop"); canvas = j_canvas(frame,256,256); j_setpos(canvas,10,60); j_setnamedcolorbg(canvas,J_WHITE); j_show(frame); j_pack(frame); /* Waiting for actions */ while(1) { if(do_work) obj=j_getaction(); else obj=j_nextaction(); if(obj==quit) break; if(obj==start) { do_work=1; j_setnamedcolor(canvas,J_WHITE); j_fillrect(canvas,0,0,256,256); } if(obj==stop) do_work=0; if(do_work) { j_setcolor(canvas,j_random()%256,j_random()%256,j_random()%256); j_drawpixel(canvas,j_random()%256,j_random()%256); } } j_quit();
Zunächst wird ein kleines Menu erstellt, das die aktiven Menupunkte ''Quit'', ''Start'' und ''Stop'' enthält. Im nächsten Schritt wird ein Canvas erzeugt:
canvas = j_canvas(frame,256,256); j_setpos(canvas,10,60); j_setnamedcolorbg(canvas,J_YELLOW);
und dem Canvas eine Größe von 256x256 Bildpunkten zugeordnet, und an die Position (10,60) gesetzt. Bezugspunkte zur Positionierung sind jeweils die oberen linken Ecken, der beiden Elemente Frame und Canvas. Somit wird die obere linke Ecke des Canvas 10 Pixel rechts und 60 Pixel unterhalb der oberen linken Ecke des Frames angeordnet.
Da der Canvas zudem dieselbe Hintegrundfarbe besitzt wie der Frame, wäre der Canvas zunächst nicht zu erkennen. Deshalb wird dem Canvas eine andere Hintergrundfarbe zugeordnet:
j_setnamedcolorbg(canvas,J_YELLOW);
Diese Funktion ist eine von vier Funktionen um Farben zu setzen:
j_setcolor(int japi_object, int r, int g, int b) j_setcolorbg(int japi_object, int r, int g, int b) j_setnamedcolor(int japi_object, int farbe); j_setnamedcolorbg(int japi_object, int farbe);
Die beiden ersten Funktionen setzen die Farben für Vordergrund und Hintergrund durch RGB Werte. Jeder Kanal kann einen Wert von 0 bis 255 annehmen. Die nächsten beiden Funktionen setzen vordefinierte Farben. Die Variable ''farbe'' kann dabei einen Wert von 0 bis 15 annehmen. Diese 16 Farben entsprechen dem alten CGA Farbmodell und sind wie folgt zugeordnet:
J_BLACK 0 J_WHITE 1 J_RED 2 J_GREEN 3 J_BLUE 4 J_CYAN 5 J_MAGENTA 6 J_YELLOW 7 J_ORANGE 8 J_GREEN_YELLOW 9 J_GREEN_CYAN 10 J_BLUE_CYAN 11 J_BLUE_MAGENTA 12 J_RED_MAGENTA 13 J_DARK_GRAY 14 J_LIGHT_GRAY 15
Wird bei einem Canvas die Hintergrundfarbe gesetzt, so wird der gesamte Inhalt des Canvas geloescht. Somit können diese Funktionen auch zum Löschen des Fensterinhaltes verwendet werden. Unfangreiche Erläuterungen zu diesen Funktionen und den Farbmodellen finden sich im Kapitel 5.
Nachdem alle graphischen Objekte erzeugt wurden, wird der Frame angezeigt:
j_show(frame); j_pack(frame);
Der Befehl j_pack() veranlaßt den Frame seine eigene Größe zu ermitteln. Dabei stellt dieser die Größe aller enthaltener Objekte und deren Position fest. Seine eigene Größe stellt nun die Vereinigungsmenge aller Objektedimensionen dar. Zusätzlich wird eine rechter und unterer Rand von 5 Pixeln hinzugegeben. Durch diese Funktion kann auf eine aufwendiges Berechnungsverfahren verzichtet werden. Alternativ zu j_pack() kann jedoch auch einem Frame mit der Funktion j_setsize() eine fixe Größe zugeordnet werden. Es macht keinen Sinn beide Funktionen zu verwenden. In diesem Falle würde immer die zuletzt verwendete Funktion gewinnen.
In der Event Loop findet sich zunächst folgende Abfrage:
if(do_work) obj=j_getaction(); else obj=j_nextaction();
Dabei ist die Variable do_work ein Flag, das gesetzt wird, wenn der Benutzer
den Menueintrag ''start'' angewählt hat. Ist das Flag gesetzt, so wird statt
j_nextaction() die Funktion j_getaction() aufgerufen. Der Unterschied der
beiden Funktionen ist, daß j_nextaction() solange blockiert, bis eine Aktion
vom Benutzer eintritt. j_getaction() hingegen kehrt sofort zurück, und
liefert entweder die Identifikationsnummer eines Objektes, oder wenn keine
Aktion vorlag, liefert die Funktion zurück. Prinzipiell kann man in
einer Event Loop stets die nicht blockierende Funktion j_getaction()
verwenden. Diese führt jedoch zu einem Busy Waiting in der Application, und
verschwendet unnötigerweise Recourcen. j_getaction() solte daher nur dann
benutzt werden, wenn die Application in einer Berechnung steckt, und dennoch
auf Benutzereingaben reagieren soll. In unserem Beispiel soll immer auf die
Befehle ''Quit'' und ''Stop'' reagiert werden.
Wird vom Benutzer der Menupunkt ''Start'' angewählt
if(obj==start) { do_work=1; j_setnamedcolorbg(canvas,J_YELLOW); }
so wird zunächst das Flag do_work gesetzt. Die folgende Anweisung setzt die Hintergrundfarbe neu. Dadurch wird der Inhalt des Canvas gelöscht.
Die eigentliche Zeichenarbeit wird von folgenden Zeilen erledigt:
if(do_work) { j_setcolor(canvas,j_random()%256,j_random()%256,j_random()%256); j_drawpixel(canvas,j_random()%256,j_random()%256); }
Dabei werden zunächst zufällig verteilte Rot-, Grün- und Blauanteile ermittelt, und als entsprechende Vordergrundfarbe gesetzt. mit dieser Farbe wird nun ein Pixel im Canvas gezeichnet. Die X- und Y-Koordinate des Punktes werden dabei ebenfalls wieder zufällig bestimmt. Der Canvas füllt sich langsam mit bunten Punkten.
Während sich der Canvas langsam mit bunten Punkten füllt, wird immer noch mit der Funktion j_getaction() auf Benutzereingaben reagiert. Ein Anklicken der Menüeintrags ''Stop'' führt somit zur Beendigung der Zeichenaktivität. Ebenso hat des Anklicken des Menüpunktes ''Quit'' das Beenden des Programms zur Folge.
An dieser Stelle soll nochmal kurz auf das eingehende Beispiel mit der Mandelbrotmenge zurückgekehrt werden. Obiges Beispielprogramm und das Mandelbrot Beispiel unterscheiden sich nur in der Berechnung der Farbe und Position eines Punktes. Während im jetzigen Beispiel die Punkte und Farben zufällig gewählt werden, werden sie sie dort durch die Mandelbrot Iteration festgelegt.
Auch ein Canvas kann einen Event zurückliefern. Dieser Event ist an die Größe des Canvas gebunden. Wird die Größe des Canvas verändert, so wird die Applikation über die Canvas ID benachrichtigt, und kann entsprechend reagieren. Wir wollen an dieser Stelle das Eingangsbeispiel mit der Mandelbrotmenge aufgreifen, und eine Version erstellen, die es dem Benutzer erlaubt, die Fentergröße zu verändern. Dazu sind nur wenige Änderungen nötig:
/* Example mandel1.c */ /* window Size */ hoehe = 240; breite = 320; : if(j_start()<0) printf("can't connect to JAPI Kernel"),exit(0); frame = j_frame("Variables Mandelbrot"); j_borderlayout(frame); menubar = j_menubar(frame); file = j_menu(menubar,"File"); calc = j_menu(menubar,"Calc"); quit = j_menuitem(file,"Quit"); start = j_menuitem(calc,"Start"); stop = j_menuitem(calc,"Stop"); canvas = j_canvas(frame,breite,hoehe); j_show(frame); j_pack(frame); x=y=-1; while(1) { if(do_work) obj=j_getaction(); else obj=j_nextaction(); if(obj==quit) break; if(obj==start) { x=y=-1; do_work=1; j_setnamedcolor(canvas,J_WHITE); } if(obj==stop) do_work=0; if(do_work) { x=(x+1)%breite; if(x==0) y=(y+1)%hoehe; if((x==breite-1) && (y==hoehe-1)) do_work=0; else { zre = xstart + x*(xend-xstart)/breite; zim = ystart + y*(yend-ystart)/hoehe; it = mandel(zre,zim,512); j_setcolor(canvas,it*11,it*13,it*17); j_drawpixel(canvas,x,y); } } if(obj==canvas) { breite = j_getwidth(canvas); hoehe = j_getheight(canvas); x=y=-1; } } j_quit(); :
Eine wichtige neue Funktion ist
j_borderlayout(frame);
Diese Funktion binden den Canvas so an den Frame, daß bei einer Größenänderung des Frames automatisch der Canvas mit vergrößert wird. Daraufhin erzeugt der Canvas einen Event, der in der Mainloop abgefragt werden kann:
if(obj==canvas) { breite = j_getwidth(canvas); hoehe = j_getheight(canvas); x=-1,y=-1; }
Das Beispielprogramm ermittelt nun die neue Hoehe und Breite des Canvas, und setzt die beiden Laufvariablen so, daß das gesamte Bild neu berechnet wird. Das wars.
Die Abbildung 2.8 und 2.9 zeigt dieses Beispielprogramm mit zwei unterschiedlichen Größen.
Nach diesem Kapitel sollte bereits jeder Programmierer in der Lage sein einfache Programme zu entwerfen und zu programieren. Die Elemente Frame, Canvas und Menüs erlauben bereits eine Vielzahl graphischer Applikationen.