import java.awt.* importiert
(AWT=Abstract Windowing Toolkit). Um diese geschickt anzuwenden, muss
man möglichst viele der
Bezeichner dieser bereitgestellten Klassen, Interfaces, Methoden und Daten mitsamt ihrer
Bedeutung genau kennen. Um deren Funktionen zu erproben, bleibt einem
häufig nichts anderes übrig, als zu experimentieren. Ich
werde im folgenden alle die Bezeichner
von Klassen, Methoden und
Attributen blau kennzeichnen, die ich den
Java-Paketen entnommen habe.
Die hier verwendete Java-Basisklasse heißt Frame. Sie ermöglicht mit ihrem Konstruktor und ihren Methoden die Erzeugung und Ausgestaltung eines Grafikfensters.
Ich werde im folgenden erklären, wie man ein Grafikfenster, in
dem eine Kurve gezeichnet werden soll, konstruiert und ausgestaltet. Das
einfachste Beispiel wird eine Unterklasse von Frame namens Grafik0 sein. Hier werden
Sie lernen, wie man ein Grafikfenster einer bestimmten Höhe und
Breite erstellt (setSize()), dessen
Hintergrundfarbe festlegt (setBackground()) und eine Kurve in
einer bestimmten Farbe zeichnet (paint()), indem winzige Geradenstücke
aneinandergereiht werden (drawLine()).
In einem zweiten Beispiel (Grafik1) wird
die Kurve von einem Parameter dt abhängen, den man interaktiv
mit Hilfe einer Schaltfläche, die Teil des Grafikfensters ist,
ändern und anschließend eine neue Zeichnung durch einen
Mausklick veranlassen kann. Die Java-Hilfsmittel sind hier schon
komplexer, insbesondere muss ein Interface namens ActionListener implementiert werden, das mit
seinen Methoden gestattet, auf Mausklicks zu reagieren.
Das Herz aller Grafikklassen ist die Methode paint(), die die Struktur
public void paint(Graphics g){..........}
besitzt und deren Block stets ausgeführt wird, wenn ein Objekt einer
Unterklasse von Frame in einem
main()-Block einer Applikationsklasse initialisiert
wird.
Dabei werden i.a. Methoden der Klasse Graphics bzw. dessen Objekte
wie die selbsterklärenden Methoden setColor() oder drawLine() benutzt
werden. Das konkret "gezeichnete" Grafikobjekt wird oben mit
g bezeichnet und ist ein Objekt der Klasse Graphics. Der Farbigkeit dienen "Farbkonstenten" der Klasse Color, wie z.B. Color.blue.
Unsere Klasse Grafik0 (s.u.) wird durch
aus der Klasse Frame abgeleitet, d.h. ist eine Unterklasse von Frame. So würde mittelspublic class Grafik0 extends Frame
Frame w = new Frame("Leeres Grafikfenster");
w.setsize(400,300); w.visible(true);
innerhalb der
main()-Methode einer Applikationsklasse ein leeres
Fenster der Größe 400x300 Pixel mit einer Titelleiste, die
den Text Leeres Grafikfenster enthält, erzeugt. Die Klasse
Frame hat also einen Konstruktor, der
einen String übergibt, der den Titel der Titelleiste
definiert. setSize() und visible() sind offensichtlich Methoden der
Klasse Frame bzw. seiner Objekte (wie
hier w).
In unserer Klasse Grafik0 wird der
Applikationsblock
static public void main( String [] args ){
Grafik0 obj=new Grafik0(
//Konstruktor uebergibt String:
"x=2.1*cos(2pi*t)+0.1*sin(2pi*10*t);"+
"y=2.1*sin(2pi*t)-0.1*cos(2pi*10*t);"+
"0<=t<=1, Schrittweite dt. B.W. 19.9.00");
}//Ende main()
die Erzeugung eines Fensters mit Zeichnung auslösen. Die
Titelleiste zeigt die Formel der parametrisierten Kurve (was sich
dahinter verbirgt, wird in der Vorlesung kurz erklärt).
Unsere Klasse Grafik0 sieht wie folgt aus:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Grafik0 extends Frame{
//DATEN:
double dt=0.001; //Zeichenschrittweite
int H=700, B=800; //Fensterhoehe, -Breite
//Ende DATEN
//KONSTRUKTOR:
public Grafik0 (String title ) {
super( title ); // Fenstertitel uebergeben
// Schliessbarkeit des Fensters ermoeglichen:
addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent w ) {
setVisible(false); dispose(); System.exit(0);
}//Ende windowClosing()
}//Ende des Konstruktors WindowAdapter()
);//Ende addWindowListener()
//Hintergrundfarbe des Fensters setzen:
setBackground(Color.lightGray);
//Groesse des Fensters setzen:
setSize(B,H);
//Fenster in die linke obere Ecke positionieren:
setLocation( 0, 0 );
//Fenster sichtbar machen:
setVisible( true );
}//Ende KONSTRUKTOR Grafik0
//METHODEN:
public double[] sincos(double t){
double[] x=new double[2];
//Nur hier steckt Mathematik:
x[0]=2.1*Math.cos(2*Math.PI*t)+0.1*Math.sin(2*Math.PI*20*t);
x[1]=2.1*Math.sin(2*Math.PI*t)-0.1*Math.cos(2*Math.PI*20*t);
return x;
}//Ende sincos()
public short[] skalierung(double x, double y){
double xMax=3, xMin=-xMax, yMax=3, yMin=-yMax;
short[] i = new short[2];
i[0]=(short) (B/10 +B*0.9*(x-xMin)/(xMax-xMin));
i[1]=(short) (H/10 +H*0.9*(y-yMin)/(yMax-yMin));
return i;
}//Ende skalierung()
//paint() legt fest, was gezeichnet wird:
public void paint (Graphics g) {
//Farbe der auszugebenden Grafik setzen
g.setColor(Color.red);
double t=0.0;
double[] x=sincos(t);
short[] i1=new short[2];
short[] i0=skalierung(x[0],x[1]);
// Linien zeichnen
while (t<=1) {
t+=dt;
x=sincos(t);
i1=skalierung(x[0],x[1]);
g.drawLine(i0[0],i0[1],i1[0],i1[1]);
i0[0]=i1[0];i0[1]=i1[1];
}//Ende while
}//Ende paint()
static public void main( String [] args ){
Grafik0 obj=new Grafik0(
"x=2.1*cos(2pi*t)+0.1*sin(2pi*20*t);"+
"y=2.1*sin(2pi*t)-0.1*cos(2pi*20*t);"+
"0<=t<=1, B.W. 11.8.01");
}//Ende main()
} // Ende class Grafik0
Die entscheidende Zeile ist die Zeile in der Methode
main(), in der ein Objekt namens obj der Klasse
Grafik0 deklariert und initialisiert wird. Da Grafik0
eine Unterklasse von Frame ist, wird
ein Grafikfenster der im Konstruktor vorgesehenen Größe
(setSize()) und Hintergrundfarbe
(setBackground()) und Position
(setLocation()) geöffnet und der
paint()-Block abgearbeitet, der eine
durch t parametrisierte Kurve mit Hilfe der Methode
drawLine() zeichnet. Etwas kryptisch
ist der paint()-Parameter
g als Objekt der Klasse Graphics, welche alle grafischen Methoden wie
drawLine(), setColor() definiert.
Die 4 Parameter von drawLine() sind
jeweils 2 Pixel-Paare, die die
Koordinaten im Grafikfenster bestimmen, wobei der Ursprung die obere
linke Ecke ist und die Pixel-Ordinate nach unten, die Pixel-Abszisse
nach rechts zeigt. Die Methode skalierung() dient der Umrechnung
von den mathematischen Koordinaten in die Pixel-Koordinaten. Die
Grafikfenstergröße wird ebenfalls in Pixel gemessen, wobei
die Auflösung des Bildschirms eingeht.
Ich empfehle, einfach einige Experimente mit diesem Programm durchzuführen, indem kleine Änderungen vorgenommen werden.
Unsere Klasse Grafik1 (s.u.) wird durch
public class Grafik1 extends Frame
implements
ActionListener{
//...................... }
aus der Klasse Frame
abgeleitet und implementiert ein Interface (das ähnlich wie eine
Oberklasse Daten und Methoden vererbt) namens ActionListener. Dieses Interface
ermöglicht es, mit seinen Methoden (u.a. actionPerformed()) auf
Events ("Aktionen") wie einen Mausklick oder das Verändern eines
Textfeldes im Grafikfenster zu reagieren.
Grafikfenster werden i.a. mit verschiedenen Arten von Schaltflächen versehen. Die Festlegung deren Gestalt ist eine Layoutaufgabe. Auch hier gibt es mächtige Java-Klassen und -Methoden, von denen ich nur Panel, Button, TextField, Label, setLayout(), GridLayout(), setForeground(), setBackground() erwähne. Diese werden im folgenden genauso wenig näher erläutert wie die Methode addWindowListener(), die das Schließen des Fensters ermöglicht. Bei eigenen Versuchen orientiere man sich einfach an den folgenden Beispielen.
Unsere Klasse Grafik1 sieht wie folgt aus:
import java.awt.*;
import java.awt.event.*;
import java.util.*;
public class Grafik1 extends Frame
implements ActionListener{
//DATEN:
double dt=0.3; //Zeichenschrittweite
/*Der Inhalt des folgenden Textfeldes kann interaktiv veraendert
werden - s. Methode actionPerformed()*/
TextField tf1 =new TextField(""+dt);//Ein Textfeld wird konstruiert
//Ende DATEN
//KONSTRUKTOR:
public Grafik1 (String title ) {
super( title ); //Konstruktor von Frame
//Schliessbarkeit des Fensters ermoeglichen:
addWindowListener(
new WindowAdapter() {
public void windowClosing( WindowEvent w ) {
setVisible(false); dispose(); System.exit(0);
}//Ende windowClosing()
}//Ende des Konstruktors WindowAdapter()
);//Ende addWindowListener()
/*ein Panel besteht aus Labels, Textfeldern, Buttons.
np1 wird am unteren Rand ("South") angebracht, enthält die
Beschriftung "Neu zeichnen" uns soll auf einen Mausklick
reagieren.
np2 besteht aus einem Label mit Beschriftung "dt" und einem
Textfield, das den Zahlenwert von dt enthält und das interaktiv
verändert werden kann. */
Panel np1 = new Panel();
Panel np2 = new Panel();
//Ein Button wird konstruiert
Button rc=new Button("Neu zeichnen");
Label l1=new Label("dt=",Label.CENTER);
np1.setLayout(new GridLayout(1,1));//Eine Zeile, 1 Spalte)
np1.setForeground(Color.red);
np1.add(rc);
add("South",np1);
np2.setLayout(new GridLayout(1,1));
np2.setBackground(Color.yellow);
add("North",np2);
np2.add(l1);
np2.add(tf1);
rc.addActionListener(this);
/*addActionListener steht in der Klasse Button
zur Verfuegung. Ihr Argument ist vom Typ ActionListener
- einem Interface, das von unserer Klasse Grafik1
implementiert wird und die Methode actionPerformed()
zur Verfuegung stellt, die unten ueberlagert wird.
Durch diese Mathode reagiert das Programm auf das
Druecken des Buttons "Neu Zeichnen" */
//Hintergrundfarbe des Fensters setzen:
setBackground(Color.lightGray);
//Groesse des Fensters setzen:
setSize(800,700);
// Fenster in die linke obere Ecke positionieren:
setLocation( 0, 0 );
// Fenster sichtbar machen:
setVisible( true );
}//Ende KONSTRUKTOR Grafik1
//METHODEN:
public double[] sincos(double t){
double[] x=new double[2];
//Nur hier steckt Mathematik:
x[0]=2.1*Math.cos(2*Math.PI*t)+
0.4*Math.sin(2*Math.PI*5.03*t);
x[1]=1.9*Math.sin(2*Math.PI*t)
-0.6*Math.cos(2*Math.PI*5.03*t);
return x;
}//Ende sincos()
public short[] skalierung(double x, double y){
double xMax=3, xMin=-xMax, yMax=3, yMin=-yMax;
short[] i = new short[2];
i[0]=(short) (120 +600*(x-xMin)/(xMax-xMin));
i[1]=(short) ( 50 +600*(y-yMin)/(yMax-yMin));
return i;
}//Ende skalierung()
//paint() legt fest, was gezeichnet wird:
public void paint (Graphics g) {
//paint() ist eine Methode der Oberklasse Frame:
super.paint( g );
// Farbe der auszugebenden Grafik setzen:
g.setColor(Color.red);
double t=0.0;
double[] x=sincos(t);
short[] i1=new short[2];
short[] i0=skalierung(x[0],x[1]);
// Linien zeichnen:
while (t<=100) {
t+=dt;
x=sincos(t);
i1=skalierung(x[0],x[1]);
g.drawLine(i0[0],i0[1],i1[0],i1[1]);
i0[0]=i1[0];i0[1]=i1[1];
}//Ende while
}//Ende paint()
public void actionPerformed(ActionEvent e){
String cmd;
cmd=e.getActionCommand();
if (cmd.equals("Neu zeichnen")){
dt=(new Double(tf1.getText())).doubleValue();
repaint(); //Methode von Frame
}//Ende if
}//Ende actionPerformed()
static public void main( String [] args ){
Grafik1 obj=new Grafik1(
"x=2.1*cos(2pi*t)+0.4*sin(2pi*5.03*t);"+
"y=1.9*sin(2pi*t)-0.6*cos(2pi*5.03*t);"+
"0<=t<=100, Schrittweite dt. B.W. 19.9.00");
}//Ende main()
} // Ende class Grafik1
Ich werde in der Vorlesung zu dieser Klasse weitere Erklärungen
geben. Diese werden verständlicher, wenn man das Programm
ausführt.
Die Methode actionPerformed()
reagiert auf einen Mausklick auf den mit "Neu Zeichnen" beschrifteten
Button, indem mittels Aufruf von repaint() der Zeichenvorgang wiederholt wird,
allerdings mit dem aktuellen, interaktiv veränderbaren Wert des
Parameters dt, der mittels Methode getText() "abgelesen" und mittels der Methode
doubleValue() der Klasse Double, dessen Konstruktor den String des
Textfeldes tf
übergibt, in eine double-Zahl verwandelt wird.