Programme mit graphischer Benuteroberfläche

Grafische Benutzeroberflächen haben sich im Bereich des PC schon lange durchgesetzt. Mit Java lassen sie sich entweder in eigenen Applikationen oder in Applets verwirklichen. Dementsprechend soll ein Graphical-User-Interface zur Interaktion mit dem Benutzer verwendet werden…

import java.awt.*;
 
class guihallo extends Frame {
 
  guihallo(String title) {
    	super(title);
	setLayout(new FlowLayout());
	add(new Button("Hi"));
	add(new Button("Exit"));
  }
 
  public static void main(String args[]) {
	guihallo app = new guihallo("Hallo, erstes Java-Proggi!");
	app.resize(300,70);
	app.show();
  }
}

Die Klasse „Frame“ wird um die eigene Klasse erweitert. Beachte, dass der Klassenname mit dem Namen der Quelldatei übereinstimmen muss!

import java.awt.*;
import java.awt.event.*;
 
public class Frame2 extends Frame {
    private Closer Handler;
 
    Frame2 () {
        Handler = new Closer ();
        setTitle ("Frame Example");
        setSize (300,120);
        addWindowListener (Handler);
        show ();
    }
 
    public static void main (String args[]) {
        Frame f;
        f = new Frame2 ();
    }
}
 
class Closer extends WindowAdapter {
    public void windowClosing (WindowEvent event) {
        System.exit (0);
    }
}

Swing

Swing stellt eine Erweiterung der Abstract Windowing Toolkit (AWT) dar. Swing wird durch das Package javax.swing.* zur Verfügung gestellt. Im folgenden Beispiel geht es um den Prinzipaufbau einer Swing-Applikation:

Eingabe

Eingabe

In diesem Abschnitt soll die Dateneingabe mit GUI-Objekten beschrieben werden. Einfache Objekte sind:

Die Eingabe „von der Konsole aus“ (Standard-Eingabe) wird im Abschnitt Ein- und Ausgabe beschrieben.

Buttons

Buttons sind wesentliche Eingabeelemente zur Interaktion zwischen Benutzer und Applikation…

Beispiel:

import java.awt.*;
 
class buttons extends Frame {
 
    buttons() {
 
        Button ein_button;
 
   	ein_button = new Button("OK");
	add(ein_button);
    }
 
    public static void main (String args[]) {
	buttons app = new buttons();
	app.resize(120,70);
	app.show();
    }
}

Radiobuttons

Unter „Radiobuttons“ verstehen wir eine Auswahlliste, deren Einträge eindeutig ausgewählt werden können. Die Auswahl wird durch das „Anklicken“ eines Buttons realisiert, der vor dem jeweiligen Begriff steht.

Beispiel:

import java.awt.*;
 
class radbutt extends Frame {
 
    radbutt() {
     	setLayout (new GridLayout(3,1,15,10));
     	CheckboxGroup gruppe = new CheckboxGroup();
     	Checkbox rad_butt1 = new Checkbox("1", gruppe, true);
     	Checkbox rad_butt2 = new Checkbox("2", gruppe, false);
     	Checkbox rad_butt3 = new Checkbox("3", gruppe, false);
     	add (rad_butt1);
     	add (rad_butt2);
     	add (rad_butt3);
    }
 
    public static void main (String args[]) {
    	radbutt app = new radbutt();
    	app.resize(200,100);
    	app.show();
    }
}

CheckButtons

Checkboxen lassen im Gegensatz zu Radiobuttons auch Mehrfachauswahlen zu…

Beispiel:

import java.awt.*;
 
class chbox extends Frame {
 
    chbox() {
     	setLayout (new GridLayout(3,1,15,10));
     	Checkbox checkbox1 = new Checkbox("1", null, true);
     	Checkbox checkbox2 = new Checkbox("2", null, false);
     	Checkbox checkbox3 = new Checkbox("3", null, false);
     	add (checkbox1);
     	add (checkbox2);
     	add (checkbox3);
    }
 
    public static void main (String args[]) {
    	chbox app = new chbox();
    	app.resize(200,100);
    	app.show();
    }
}

Texteingabe

Texte sollen in sogenannten Textfeldern eingegeben und von da aus weiter verarbeitet werden.

Beispiel:

import java.awt.*;
 
public class textein extends Frame {
 
    textein() {
    	TextField eingabe = new TextField("Hier eingeben ;-)", 30);
    	add(eingabe);
    }
 
    public static void main (String args[]) {
    	textein app = new textein();
    	app.resize(200,100);
    	app.show();
    }
}

Mit der Methode getText() wird der Text des Eingabefeldes ausgelesen - getText() gibt dabei eine Zeichenkette (String) zurück. Sollen Zahlen eingelesen werden, so müssen die übergebenen Zeichenketten in Zahlentypen konvertiert werden:

Double.valueOf(string(variable)).doubleValue()

Mehrzeilige Textfelder werden mit Hilfe von TextArea() festgelegt: TextArea(String s, int zeilen, int spalten, int scrollbars) übergibt die Zeichenkette in ein Textfeld mit definierter Zeilen- und Spaltenzahl. Außerdem werden Scrollbalken definiert:

Aufgabe:

Erweitere das Beispiel um einige weitere Texteingabefelder!

Auswahlfelder

Sobald ein Auswahlfeld fokussiert wird, erscheint eine Liste aller Einträge. Per Mausklick wird nun der gewünschte Eintrag ausgewählt…

Beispiel:

import java.awt.*;
 
public class auswahl extends Frame {
 
    auswahl() {
     	Choice wahl = new Choice();
     	wahl.addItem("Pascal");
     	wahl.addItem("Delphi");
     	wahl.addItem("Java");
     	wahl.addItem("JBuilder");
     	wahl.addItem("NetBeans");
     	wahl.addItem("Forte4Java");
     	wahl.addItem("KDevelop");
     	add(wahl);
    }
 
    public static void main (String args[]) {
    	auswahl app = new auswahl();
    	app.resize(200,100);
    	app.show();
    }
}  

Ausgabe

Manche (auch leistungsfähige) Java-Programme geben auf der Standard-Ausgabe (auf der Textkonsole) aus. Dies wird im Abschnitt Ein- und Ausgabe beschrieben. An dieser Stelle soll die Ausgabe auf grafischen Objekten beschrieben werden:

Label

Label dienen zur Ausgabe von Text auf eine bestimmte Fläche des geöffneten Fensters. Der Text wird lediglich ausgegeben - es besteht keine Möglichkeit zum Editieren. Mit der Methode getText() kann der Text eines Labels abgefragt werden, mit der Methode setText() wird der Text des Labels verändert.

Beispiel:

Es werden 3 Labels verwendet - die Texte zweier Label werden beim Anlegen definiert, der Text des dritten Labels wird mit der Methode setText() vergeben.

import java.awt.*;
 
public class label extends Frame {
 
    Label label3 = new Label();
 
    label() {
    	super("Label");
    	setLayout(new FlowLayout());
    	Label label1 = new Label("Label1");
    	add(label1);
    	Label label2 = new Label("Label2");
    	add(label2);
    	add(label3);
    }
 
    public static void main (String[] arguments) {
    	label proggi = new label();
 
    	proggi.label3.setText("Text gesetzt");
 
    	proggi.setSize(300,100);
    	proggi.setLocation(100,100);
    	proggi.show();
    }
}

Beachte die Variablen-Deklaration: Die Variable label3 wird als sogenannte „Instanzvariable“ der Klasse label() definiert. Auf sie kann daher auch von außerhalb zugegriffen werden (beachte die korrekte Dereferenzierung…).

setLayout(new FlowLayout());

legt das Standartlayout fest, mit dem alle GUI-Elemente hintereinander im Fenster angeordnet werden.

Aufgabe:

Erstelle eine Applikation, die beim Drücken eines Buttons den Inhalt eines Textfeldes in einem Label ausgibt!

import java.awt.*;
import java.awt.event.*;
 
public class ereignis1 extends Frame {
 
    static TextField tf1 = new TextField("Hier eingeben",20);
    static Label label1 = new Label("Label 1");
 
    public static void main (String[] arguments) {
 
      Frame fenster = new Frame("Ein komplettes Programm");
 
      WindowListener wl = new WindowAdapter() {
 
          public void windowClosing(WindowEvent e) {
            System.exit(0);
          }
 
      };
 
      ActionListener al = new ActionListener(){
 
          public void actionPerformed(ActionEvent e){
            String s = tf1.getText();
            label1.setText(s);
          }
 
      };
 
      fenster.setLayout(new FlowLayout());
      fenster.addWindowListener(wl);
      fenster.setSize(500,200);
 
 
      Button b1 = new Button("Button 1");
      b1.addActionListener(al);
      fenster.add(b1);
      fenster.add(tf1);
      fenster.add(label1);
 
      fenster.show();
    }
}

Grafik-Ausgabe

Einfache Grafikelemente werden durch gerade Linien erzeugt. Sie werden mit Hilfe der „paint()“- Methode ausgeben, die nach der Initialisierung der Applikation aufgerufen wird… Weitere Grafikmethoden werden bei Applets„-„Grundlagen“ angeführt.

Beispiel:

import java.awt.*;
 
public class grafik extends Frame {
 
    grafik() {
        super("Grafikausgabe");
    }
 
    public void paint (Graphics g) {
    	int i;
    	int j;
 
    	g.setColor(Color.red);
 
    	for (i=1;i<10;i++) {
    	    for (j=1;j<10;j++) {
    	        g.drawLine(50+i*45,20,500-j*45,200);
    	    }
    	}
    }
 
    public static void main (String args[]) {
        grafik app = new grafik();
        app.resize(550,200);
        app.show();
    }
}

Textausgabe

Texte werden mit Hilfe der Methode „paint()“ ausgegeben, die nach der Initialisierung aufgerufen wird.

Beispiel:

import java.awt.*;
 
public class textaus extends Frame {
 
    textaus() {
        super("Textausgabe");
    }
 
    public void paint(Graphics g) {
	g.drawString("Informatik ist schön",30,60);
    }
 
    public static void main (String args[]) {
        textaus app = new textaus();
        app.resize(250,100);
        app.show();
    }
}

Layout

Alle GUI-Objekte werden auf Applet- oder Applikationsfenstern mit Hilfe verschiedener Layout-Managern angeordnet. Dabei stehen folgende Layouts zur Verfügung:

Beispiel:

Fünf Objekte (Zwei Labels, zwei Buttons und eine Checkbox) werden gemäß dem BorderLayout angeordnet.

import java.awt.*;
 
public class layout extends Frame {
 
    layout() {
        super("BorderLayout");
        setLayout(new BorderLayout());
        Label label1 = new Label("Label1");
        add(label1, "East");
        Label label2 = new Label("Label2");
        add(label2, "South");
        Button b1 = new Button("Button1");
        add(b1, "West");
        Button b2 = new Button("Button2");
        add(b2, "North");
        Checkbox cb = new Checkbox("Tja");
        add (cb, "Center");
    }
 
    public static void main (String[] arguments) {
        layout proggi = new layout();
 
        proggi.setSize(300,100);
        proggi.setLocation(100,100);
        proggi.show();
    }
}

Aufgabe:

Positioniere Textfelder, Checkbuttons und Radiobuttons und experimentiere mit verschiedenen Layouts!

Java arbeitet streng objektorientiert. Dazu werden sogenannte „Klassen“ erstellt, die die ihnen zugedachten Aufgaben ausführen sollen. Zu einer solchen Klasse gehören die Methoden (mit oder ohne Rückgabewerte) und die Variablen, die innerhalb der Klasse benötigt werden. Jedes neu erstellte Programm erweitert entweder eine bestehende Klasse oder stellt eine neue Klasse dar. Abgeleitete Klassen „erben“ im Allgemeinen die Eigenschaften der übergeordneten Klasse(n).

Java-Programme, die unter einer grafischen Benutzeroberfläche (GUI) laufen, erweitern bestehende Klassen (z.Bsp. „Frame“ oder „JFrame“). Auf diese Weise muss sich der Programmierer beispielsweise nicht mehr um die Darstellung auf dem Bildschirm kümmern. Eine andere wichtige Klasse stellt die Klasse „Applet“ dar…

Applikationen werden unter dem sogenannten Java Runtime Environment (JRE) ausgeführt. Die Programme wurden mit dem Javacompile (javac) in den sogenannten Java-Bytecode übersetzt. Das auf dem jeweiligen Rechner vorhandene IRE übernimmt schließlich die Ausführung des Bytecodes (Beachte: dadurch werden die Applikationen plattformunabhängig…).

Grundsätzlich besteht jede Applikation darin, dass eine eigene (neue) Klasse definiert wird. Diese Klasse muss mindestens eine Methode enthalten: public static void main(String arguments[]). Sobald die Applikation gestartet wird, wird die Methode 'main' abgearbeitet - die Applikation „läuft“ ;-)

Sollen Elemente des graphic user interface (GUI) verwendet werden, so sollten im Allgemeinen die Packages 'awt.*' und 'awt.event.*' importiert werden. Damit stehen im Wesentlichen folgende Objekte zur Verfügung:

Um Ereignisse in der Applikation verarbeiten zu können sind sogenannte Event Listener nötig, die als sogenannte „Interfaces“ die Schnittstelle zwischen Applikation und Benutzer herstellen (vgl. auch „Applets - Events“ auf dieser Seite!):

*

GUI-Applikationen

Für interaktive Java-Programme muss gelten:

1. Die Applikation bzw. das Applet muss entsprechende Interfaces implementieren.

2. Jedes GUI-Element muss mit dem entsprechenden Event-Listener verbunden werden.

Für jedes Event-Listener-Interface gibt es sogenannte Adapterklassen, mit denen in inneren Klassen die Methoden überschreiben kann, die man für seine Anwendung benötigt (z.Bsp. WindowAdapter, MouseAdapter, MouseMotionAdapter). Das Implementieren der entsprechenden Interfaces in der Kopfzeile der Klassendefinition entfällt dabei…

Beispiel:

Die winzige Java-Applikation soll ordnungsgemäß beendet werden, indem der Benutzer das „Schließen“-Icon anklickt…

import java.awt.*;
import java.awt.event.*;
 
public class fensterzu extends Frame {
 
    fensterzu() {
    	super("Ein kompettes Proggi");
    }
 
    public static void main (String[] arguments) {
    	fensterzu proggi = new fensterzu();
    	WindowListener wl = new WindowAdapter() {
    	    public void windowClosing(WindowEvent e) {
    	    	System.exit(0);
    	    }
    	};
    	proggi.addWindowListener(wl);
    	proggi.setSize(300,100);
    	proggi.show();
    }
}

Frame - stellt ein (Programm)Fenster mit Titelleiste zur Verfügung. Die Methode super() vergibt einen Titel.

WindowAdapter() stellt das Reagieren auf „Fenster-Ereignisse“ sicher - hier soll das Schließen des Fensters realisiert werden.

addWindowListener() fügt das Windows-Interface hinzu.

setSize() legt die Breite und Höhe des Fensters fest.

show() macht das Fenster am Bildschirm sichtbar.

setLocation() legt die Koordinaten der linken oberen Ecke des Fensters fest - hier wird diese Methode nicht verwendet, daher werden Default-Werte verwendet. Voreingestellt sind die Koordinaten (0/0).

Aufgabe:

Erstelle eine kleine Applikation, die beim Drücken eines Buttons den Inhalt eines Textfeldes in einem Label ausgibt.

import java.awt.*;
import java.awt.event.*;
 
public class ereignis1 extends Frame {
 
    static TextField tf1 = new TextField("Hier eingeben",20);
    static Label label1 = new Label("Label 1");
 
    public static void main (String[] arguments) {
 
      Frame fenster = new Frame("Ein komplettes Programm");
 
      WindowListener wl = new WindowAdapter() {
 
          public void windowClosing(WindowEvent e) {
            System.exit(0);
          }
 
      };
 
      ActionListener al = new ActionListener(){
 
          public void actionPerformed(ActionEvent e){
            String s = tf1.getText();
            label1.setText(s);
          }
 
      };
 
      fenster.setLayout(new FlowLayout());
      fenster.addWindowListener(wl);
      fenster.setSize(500,200);
 
 
      Button b1 = new Button("Button 1");
      b1.addActionListener(al);
      fenster.add(b1);
      fenster.add(tf1);
      fenster.add(label1);
 
      fenster.show();
    }
}

Aufgabe: Berechne die Fläche eines Kreises (mittels JavaEditor).

import java.awt.*;
import java.awt.event.*;
 
/**
  *
  * Beschreibung
  *
  * @version 1.0 vom 10.06.2010
  * @author
  */
 
public class progframe1 extends Frame {
  // Anfang Attribute
  private Label label1 = new Label();
  private Label label2 = new Label();
  private Label label3 = new Label();
  private Button button1 = new Button();
  private NumberField numberField1 = new NumberField();
  // Ende Attribute
 
  public progframe1(String title) {
    // Frame-Initialisierung
    super(title);
    addWindowListener(new WindowAdapter() {
      public void windowClosing(WindowEvent evt) { dispose(); }
    });
 
    int frameWidth = 289;
    int frameHeight = 300;
    setSize(frameWidth, frameHeight);
 
    Dimension d = Toolkit.getDefaultToolkit().getScreenSize();
    int x = (d.width - getSize().width) / 2;
    int y = (d.height - getSize().height) / 2;
    setLocation(x, y);
    Panel cp = new Panel(null);
    add(cp);
 
    // Anfang Komponenten
    label1.setBounds(24, 24, 43, 16);
    label1.setText("Radius");
    label1.setFont(new Font("MS Sans Serif", Font.PLAIN, 13));
    cp.add(label1);
    label2.setBounds(24, 80, 41, 16);
    label2.setText("Fläche");
    label2.setFont(new Font("MS Sans Serif", Font.PLAIN, 13));
    cp.add(label2);
    label3.setBounds(88, 80, 123, 16);
    label3.setText("");
    label3.setFont(new Font("MS Sans Serif", Font.PLAIN, 13));
    cp.add(label3);
    button1.setBounds(120, 160, 123, 25);
    button1.setLabel("Berechne Fläche");
    button1.addActionListener(new ActionListener() {
      public void actionPerformed(ActionEvent evt) {
        button1_ActionPerformed(evt);
      }
    });
    cp.add(button1);
    numberField1.setBounds(88, 24, 121, 24);
    numberField1.setText("");
    cp.add(numberField1);
    // Ende Komponenten
 
    setResizable(false);
    setVisible(true);
  }
 
  // Anfang Methoden
  public void button1_ActionPerformed(ActionEvent evt) {
    // TODO hier Quelltext einfügen
    Float r = numberField1.getFloat();
    Float flaeche = r*r*(float)Math.PI;
    String fl = flaeche.toString();
    label3.setText(fl);
  }
 
  // Ende Methoden
 
  public static void main(String[] args) {
    new progframe1("progframe1");
  }
}

Wurfbahnen

Die Verwendung von Rechenanlagen hat sich seit langem für die numerische Behandlung von (mehr oder weniger einfachen) Fragestellungen aus der Physik bewährt. An dieser Stelle sollen Bahnkurven von Körpern dargestellt werden - die Wurfparabel eines auf der Erdoberfläche horizontal geworfenen Körpers soll näherungsweise „Punkt für Punkt“ berechnet und gezeichnet werden. Beispiel:

Aus der bekannten Anfangsgeschwindigkeit und der bekannten Fallbeschleunigung lässt sich für jeden Zeitschritt (hier 0.5) die neue Geschwindigkeit vneu = valt + a*dt berechnen. Kennt man die Geschwindigkeit so lässt sich aus der aktuellen Position des Körpers der im Zeitschritt zurückgelegte Weg berechnen: Die alte und die neue Position werden mit einer Linie verbunden - auf diese Weise erhält man die Bahnkurve des Körpers…

import java.awt.*;
import java.awt.event.*;
 
public class wurfbahn extends Frame {
 
    wurfbahn() {
        super("Horizontaler Wurf");
    }
 
    public static void main (String[] arguments) {
        wurfbahn proggi = new wurfbahn();
        WindowListener wl = new WindowAdapter() {
            public void windowClosing(WindowEvent e) {
                System.exit(0);
            }
        };
        proggi.addWindowListener(wl);
	proggi.setLocation(100,100);
        proggi.setSize(400,400);
        proggi.show();
    }
 
    public void paint (Graphics g) {
	double xalt,yalt,x,y,vx,vy,ax,ay,dt;
 
	dt=0.5;
	xalt=0;
	yalt=40;
	x=0;
	y=40;
	vx=40;
	vy=0;
	ax=0;
	ay=9.81;
 
	do {
	    vx=vx+ax*dt;
	    vy=vy+ay*dt;
	    x=x+vx*dt;
	    y=y+vy*dt;
	    g.drawLine((int)xalt,(int)yalt,(int)x,(int)y);
	    xalt=x;
	    yalt=y;
 
	} while ((x<400) && (y<400) && (x>=0) && (y>=01));
	g.drawString("hallo",10,10);
 
    }
}

Da die Methode drawLine(xalt, yalt, xneu, yneu) nur ganze Zahlen als Parameter akzeptiert, werden die Rechenergebnisse der reellen Zahlen in ganzzahlige Ergebnisse umgewandelt: Dies geschieht hier durch einfache Typenkonversion durch das vorangestellte “(int)„.

Aufgabe:

Erweitere die obige Applikation mit Eingabeflächen zu vx und vy!

Satellitenbahnen

Die Bahnkurve eines Satelliten, der um die Erde kreist, soll punktweise berechnet und - maßstäblich verkleinert - ausgegeben werden. Dabei wird das „Gerüst“ einer Applikation und die Methode paint() verwendet…

Beispiel:

Aus der Graviationskraft in einem Punkt des Erdschwerefeldes kann die Beschleunigung auf einen Satelliten, aus der Beschleunigung der Geschwindigkeitszuwachs, und aus der neuen Geschwindigkeit die Verschiebung des Satelliten (jeweils in einem bestimmten Zeitschritt) berechnet werden.

import java.awt.*;
import java.awt.event.*;
 
public class satellit extends Frame {
 
    satellit() {
	super("Bahnkurve eines Satelliten");
    }
 
    public static void main (String[] args) {
	satellit proggi = new satellit();
	WindowListener wl = new WindowAdapter() {
		public void windowClosing(WindowEvent e) {
		    System.exit(0);
		}
	    };
	proggi.addWindowListener(wl);
	proggi.setLocation(100,100);
	proggi.setSize(400,400);
	proggi.show();
    }
 
    public void paint (Graphics g) {
	double GM, r, r3, x, y, vx, vy, ax, ay, dt, alpha, er;
	int zaehler;
 
	zaehler = 120;
	GM = 392000000000000.0;
	er = 6370000;
	alpha = 0;
	vx = 0;
	vy = 5500;
	dt = 500;
	x = 3*er;;
	y = 0;
 
	g.setColor(Color.white);
	g.fillRect(10,10,380,380);
	g.setColor(Color.red);
	g.drawOval(200 - (int)(er/(20*er)*400),
		   200 - (int)(er/(20*er)*400),
		   (int)(er/(20*er)*800),
		   (int)(er/(20*er)*800));
	g.setColor(Color.blue);
 
	for (int i=1;i<zaehler;i++) {
	    r3 = Math.sqrt(x*x+y*y);
	    r=r3*r3*r3;
	    ax=-GM*x/r;
	    ay=-GM*y/r;
	    vx=vx+ax*dt;
	    vy=vy+ay*dt;
	    x=x+vx*dt;
	    y=y+vy*dt;
 
	    g.fillRect(200+(int)(x/(20*er)*400),200+(int)(y/(20*er)*400),1,1);
	}
    }

Aufgabe:

Erweitere das Programm so, dass die „Starthöhe“, die „Anfangsgeschwindigkeit“, der „Abschusswinkel“ und der „Zeitschritt“ vom Benutzer gewählt werden kann (Texteingabefelder)! Ausserdem soll ein Button das Neuzeichnen der Satellitenbahn starten.