.: java - grafische programmierung :.
 
abyter.de \\ workshops

Einführung
Bis jetzt bestanden unsere Anwendungen nur aus hässlichen DOS-Zeilen. Dieser Look ist jedoch schon seit einigen Jahren (man kann fast schon von einem Jahrzehnt sprechen) nicht mehr zeitgemäß. Da kann unsere Anwendung auch noch so innovativ sein, die meisten Leute werden sie wegen der veralteten Oberfläche nicht nutzen wollen.
Java wäre aber keine gute Programmiersprache wenn es für dieses Problem nicht auch eine Lösung gäbe. Das grundsätzliche Problem der grafischen Programmierung ist das Betriebssystem. Keiner wird mir widersprechen, wenn ich behaupte, dass alle Betriebssysteme unterschiedlich aussehen. Man könnte sich zwar auf eines beschränken, dann jedoch wäre der Gedanke von Java, nämlich gute Javaprogramme für alle Betriebssysteme, zerstört.

AWT
Java hat dies mit dem AWT, dem Abstract Window Toolkit gelöst; nur die Elemente die wirklich jede grafische Oberfläche implementiert (d.h. eingebaut) hat, werden eingesetzt. Die Virtual Machine (Laufzeitumgebung im Betriebssystem) von Java greift direkt auf Betriebssystemfunktionen zur Erzeugung von z.B. Buttons zu.
Nach ersten AWT-Versionen, die sich ganz strikt an diesen Grundsatz gehalten haben, wurde den Architekten von Java klar, dass das Leistungsangebot nicht für die Zukunft ausreicht. Darum ist man mit den Java Foundation Classes (JFC) einen anderen Weg gegangen. Man hat einfach die zusätzlichen Elemente komplett in Java eingebaut.

Fenster mit AWT
Wir wollen mal ganz einfach mit dem Fenster beginnen. Das Fenster (in Java der Frame) dient als Grundlage aller Dialoge mit dem Benutzer. Aus diesem Grund soll es auch die Grundlage unserer Arbeit mit dem AWT sein.
Wie schon erwähnt handelt es sich bei dem AWT um ein Paket von Java, aus diesem Grund muss es auch wie gewohnt eingebunden werden. Danach kann man ganz bequem die Klassen wie Frame (für Fenster) aus dem Paket nutzen. So sieht der Quelltext für ein kleines Fenster aus:

import java.awt.*;
public class Fenster1 extends Frame
{
public Fenster1()
{
super("Unser erstes Fenster...");
this.setSize(300,300);
this.show();
}

public static void main(String args[])
{
Fenster1 f = new Fenster1();
}
}

Wie an Quelltext zu sehen ist, werden alle Attribute und Methoden der Klasse Frame an unsere selbsterstellte Klasse Fenster1 vererbt. Neben dem Standardkonstruktor von Frame existiert noch ein weiterer, mit dem wir den Namen in der Titelleiste bestimmen können. Möchte man den Titel jedoch auch noch während der Laufzeit noch einmal ändern, so bietet sich die Methode setTitle(String str) an. Mit .setSize() wird die Größe des Fensters angegeben. Und erst mit der Anweisung .show() wird das Fenster sichtbar.

das erste Fenster

Wenn wir nun unser erstes Fenster einmal ausprobieren, so merken wir, dass das Fenster ohne unser Zutun schon recht viel kann. So kann man das Fenster vergrößern, verkleinern oder verschieben. Leider lässt sich das Programm aber noch nicht beenden. Wenn man auf das Kreuz (in Windows) drückt passiert nichts. Das ist verständlich, schließlich haben wir noch keine Ereignisbehandlungsroutine dafür geschrieben. Ohne diese Routine ist das Beenden nur durch drücken von [Str]+[C] im Konsolenfenster möglich.

Die paint()-Methode
Unser Fenster kann zwar so tolle Sachen wie größer oder kleiner werden, jedoch ist es sehr leer. Was soll man mit so einem Fenster denn anfangen?
Naja, es gibt aber Methoden die uns helfen das Fenster schöner und sinnvoller zu machen. Als nächster Schritt soll nämlich jetzt Text in unserem Fenster stehen. Dafür setzen wir die Methode paint() ein und übergeben dieser ein Objekt der Klasse Graphics. Die Klasse Graphics stellt eine große Anzahl von Methoden zum Erzeugen von Grafikobjekten (Text, Linien, Rechtecke) zur Verfügung, unter anderem auch die Methode drawString. Diese Methode ist für das Zeichnen von Text auf das Fenster zuständig.
So sieht der Quelltext für ein Fenster mit Text aus:

import java.awt.*;

public class Fenster2 extends Frame
{
public Fenster2()
{
super("Unser zweites Fenster...");
this.setSize(300,150);
this.show();
}

public void paint (Graphics g)
{
g.drawString("Hallo Welt...",100,60);
}

public static void main(String args[])
{
Fenster2 f = new java4u();
}
}

Man kann nur in der paint()-Methode auf das Graphics-Objekt zugreifen. Die paint()-Methode wiederum ist eigentlich zum Neuzeichnen des Fensters gedacht. Aber dadurch, dass das Graphics-Objekt an die paint()-Methode übergeben wird, wird auch bei jedem Neuzeichnen der Text mitaktualisiert. Das Neuzeichnen ist übrigens immer dann notwendig, wenn das Fenster verschoben, vergrößert oder verkleinert wurde. Da drawString mit Koordinaten arbeitet, wird durch das Neuzeichnen mittels paint() immer an der richtigen Stelle geschrieben.

Fenster mit Text

Das Graphics-Objekt bietet einige Zusatzfunktionen, so speichert es z.B. die Komponente auf der zu zeichnen ist, die Koordinaten des Zeichenbereichs und die aktuelle Schriftart und Farbe.

Linien
So nun wollen wir das Graphics-Objekt etwas anspruchsvoller nutzen. Wir haben ja schon erfahren, dass das Graphics-Objekt eine Vielzahl an Zeichenoperationen bietet. Neben dem Zeichnen von Text kann man auch Linien zeichnen lassen. Dies wollen wir nun tun. Wir wollen einen sogenannten Siemens-Stern zeichnen, d.h. es wird ein Stern der aus einigen Linien die im 360° Winkel angeordnet sind gezeichnet.
Das Fenster wird wie du sicher schon bemerkt hast als Koordinatensystem, behandelt. Der Ursprung (0,0) befindet sich in der oberen linken Ecke. Ein ideales Spielfeld für die Mathematik also!
Zum Zeichnen einer Linie wird die Methode drawLine verwendet, die folgendermaßen aufgebaut ist:
drawLine(int x1, int y1, int x2, int y2);

Ein Fenster in dem ein solcher Siemensstern gezeichnet wir sieht im Quelltext so aus:

import java.awt.*;
public class Fenster3 extends Frame
{
public Fenster3()
{
super("Unser drittes Fenster...");
this.setSize(500,200);
this.show();
}
public void paint (Graphics g)
{
int laenge=50;
int x2=0;
int y2=0;
for (int i=0; i<360; i+=15)
{
y2= 100-(int)(Math.sin (Math.toRadians(i))*laenge);
x2= 250-(int)(Math.cos (Math.toRadians(i))*laenge);
g.drawLine(250,100, x2, y2);
}
}

public static void main(String args[])
{
Fenster3 f = new Fenster3();
}
}

Das Zeichnen der Linien ist nicht schwer, denn der Startpunkt ist immer gleich (250,100), nur die Endpunkte müssen berechnet werden.

Fenster mit Siemensstern

Rechtecke
Bis jetzt waren alle unsere Objekte von Graphics einfarbig. Nun wollen wir den Inhalten unserer Fenster mal etwas Farbe einhauchen. Um die Farbe zu verändern, wird das Attribut color der Klasse Graphics mit der Methode setColor verändert.
Diesmal möchte ich auch nicht nur ein Rechteck ausprobieren, ich probiere mal alle möglichen Rechtecke aus, die Definition davon kann man wie von jedem Objekt aus der API-Dokumentation der JDK entnehmen. So soll unser Fenster mal aussehen:

Fenster mit farbigen Quadraten

Dafür brauchen wir folgenden Quelltext:

import java.awt.*;
public class Fenster4 extends Frame
{
public Fenster4()
{
super("Unser viertes Fenster...");
this.setSize(500,200);
this.show();
}

public void paint(Graphics g)
{
g.setColor(Color.BLACK);
g.drawRect(50,50,50,50);
g.setColor(Color.RED);
g.fillRect(110,50,50,50);
g.setColor(Color.BLUE);
g.drawRoundRect(170,50,50,50,5,5);
g.setColor(Color.GRAY);
g.fillRoundRect(230,50,50,50,10,10);
g.setColor(Color.ORANGE);
g.draw3DRect(290,50,50,50, true);
g.setColor(Color.GREEN);
g.fill3DRect(350,50,50,50,true);
}

public static void main(String args[])
{
Fenster4 f = new Fenster4();
}
}

Ereignisverarbeitung
Bis jetzt hatten unsere Programme den Nachteil, dass sie sich nicht so wie man es gewohnt ist beenden lassen. Man musste immer den Umweg über die Eingabekonsole gehen. Diesen Nachteil wollen wir nun ausmerzen!
Wie ich schon damals erwähnt hatte, ist das Beenden von Programmen ein Ereignis. Und zwar ein Frame-Ereignis. Java arbeitet mit Listenern, die auf ein bestimmtes Ereignis warten, diese Listener müssen erst registriert werden. Grundsätzlich werden die Listener über eine Methode im Stil addWindowListener registriert (Window kann auch durch andere Ausdrücke ersetzt werden).
Die Methode ist folgendermaßen aufgebaut: addWindowListener(WindowListener)
Die Methode verlangt nach einem Listener, der in der Klasse WindowListener steht. Wenn man in der API dort nachsieht erkennt man, dass es sich nicht um eine Klasse, sondern um ein Interface handelt.
Ein Interface ist eine Klasse die nur den Methodenprototypen enthält, d.h. die Methoden haben nur einen Kopf, aber keine Anweisung (Quellcoderumpf).
Das Interface hat sieben Methoden, von der aber nur eine für uns interessant ist: windowClosing(WindowEvent e).
Immer wenn ein Interface mehr als eine Methode hat, gibt es so genannte Adapterklassen, die das Interface beinhalten (also alle Methoden mit einem leeren Quellcoderumpf). Wir greifen also über einen Adapter auf die WindowListener-Funktionalität von Java zu und haben durch die Interface-Architektur die Möglichkeit den Listener an unsere Applikation anzupassen. Wir haben also freie Gestaltungsfreiheit ohne einengende Vorgaben durch Java.
Das hört sich jetzt kompliziert an, wenn man es aber erst im Quelltext siehst, wird man merken, dass alles ganz logisch ist. Nun also der Quelltext:

import java.awt.*;
public class Fenster5 extends Frame
{
private MyWindowListener myWindowListener = new MyWindowListener();

public Fenster5()
{
super("Unser fünftes Fenster...");
this.setSize(300,150);
this.show();
this.addWindowListener(myWindowListener);
}

public void paint(Graphics g)
{
g.drawString("Hallo Welt, nun schaut doch mal!",100,60);
g.drawString("Mich kann man beenden!", 130,60);
}

public static void main(String args[])
{
Fenster5 f = new Fenster5();
}
}
MyWindowListener.java
import java.awt.event.*;

public class MyWindowListener extends WindowAdapter
{
public void windowClosing(WindowEvent e)
{
System.exit(0);
}
}
Im Konstruktor (Fenster6()) wird die Ereigniskette aufgebaut, in dem der Methode addWindowListener das Objekt myWindowListener übergeben wird. Das eigentliche Beenden findet wie schon angesprochen in der selbst mit Quelltext versehenen Methode windowClosing in der Klasse MyWindowListener statt. Das Beenden selbst lässt sich mit folgender Anweisung bewerkstelligen: System.exit(0); aber man könnte noch mehr "TamTam" machen und noch Meldungen ausgeben, das Interface-System lässt uns da freie Hand.

Weiter auf der nächsten Seite>


Related Workshops: Allgemeines \\ Java Einführung \\ Arbeit mit dem JCreator \\ Programmieren mit Java \\ Programmiergrundlagen \\ Klassen-Grundlagen \\ Datenbankprogrammierung
Related Files: JCreator LE

Workshop als PDF

<Zurück

© by www.abyter.de (Martin Monshausen)