8. GUI und API für die Klasse Mathematik
8.1 GUI und Ereignisbehandlung
8.1.1 Eine JFrame-Vorlage step bei step
 
Step by step Wir wollen Schritt für Schritt ein Programm aufbauen, das zur Ausgabe ein Fenster benutzt, wie wir es z.B. von Windows gewohnt sind. Nach jedem Schritt compiliere man den Quelltext und beobachte, was passiert, wenn man das Programm startet.
Wichtig ist: Wir beschreiben die Auswirkungen, die die Veränderungen bei jedem weiteren Schritt verursachen. Auf die Erklärung vieler Details müssen wir an dieser Stelle verzichten, sie werden im Laufe des Kurses immer deutlicher.
 
Schritt 1
public class HalloWelt{
  public static void main(String[] args){

  }
}
  Das Programm besteht fast nur aus seinen Rumpfbestandteilen, die main(..) - Methode ist leer.
 
Schritt 2
public class HalloWelt{
  public HalloWelt(){
                       
  }                   
  public static void main(String[] args){

  }
}
  Ein so genannter Konstruktor ist angelegt, besitzt aber noch keine besondere Funktionalität. Wir erinnern uns, man erkennt ihn daran, dass er den gleichen Namen trägt, wie die Klasse. Hinter dem Konstruktornamen steht immer eine Parameterliste in runden Klammern; in unserem Fall ist die Liste leer. Dieser Konstruktor wird vom Compiler auchangelegt, wenn wir ihn nicht wie hier explizit implementieren. Insofern unterscheidet sich unser Programm zu seinem Vorläufer nicht.
 
Schritt 3
public class HalloWelt{
  public HalloWelt(){

  }
  public static void main(String[] args){
     new HalloWelt();
  }
}
  Der Konstruktor wird aufgerufen, um beim Starten des Programms ein Objekt der Klasse anzulegen. Das Programm 'tut noch immer nichts'.
 
Schritt 4
import javax.swing.*;                  
public class HalloWelt extends JFrame{
  public HalloWelt(){

  }
  public static void main(String[] args){
     new HalloWelt();
  }
}
  Wir lassen unsere Klasse von der Klasse JFrame erben. Das Erben von der Klasse JFrame wird durch extends JFrame kenntlich gemacht. Statt
extends JFrame müssten wir eigentlich extends javax.swing.JFrame schreiben., denn die Klasse JFrame liegt in dem Paket jawax.swing. Die kürzere Schreibweise können wir benutzen, wenn wir das Paket mittels import javax.swing.*; einbinden. 
Dass die letzte Veränderung im Quelltext auch beim laufenden Programm sichtbar wird setzt eine weitere kleine Veränderung voraus:
 
Schritt 5
import javax.swing.*;
public class HalloWelt extends JFrame{
  public HalloWelt(){
     setVisible(true);
  }
  public static void main(String[] args){
     new HalloWelt();
  }
}
  Wir rufen die von JFrame geerbte Methode setVisible(boolean b) auf. Durch das Vererben ist diese Methode zu einer Methode von HalloWelt geworden und kann ohne Punktnotation aufgerufen werden. Man könnte  statt

setVisible(true) deshalb auch

this.setVisible(true)

schreiben können.

Anmerkung:
Tatsächlich hat
java.swing.JFrame die Methode setVisible(boolean b) selbst wieder geerbt und zwar von von der Klasse java.awt.Frame, diese von java.awt.Window, diese wiederum  von java.awt.Container und diese schließlich von java.awt.Component, in der die Methode schließlich implementiert ist.

Jetzt erscheint beim Starten des compilierten Programms in der linken oberen Ecke des Bildschirms ein kleines Fenster, das man, wie man es von Fenstern gewohnt ist, mit der Maus aufziehen kann. Es hat auch die üblichen Schalter in der rechten oberen Ecke, um das Fenster minimieren, maximieren oder auch zu schließen zu können. All diese Eigenschaften hat unser Programm von JFrame geerbt, müssen also nicht extra programmiert werden. Was offensichtlich noch fehlt, ist ein Titel des Fensters. Wir wollen versuchen, diesen Mangel im nächsten Schritt zu beheben.
 

Schritt 6
import javax.swing.*;
public class HalloWelt extends JFrame{
  public HalloWelt(String titel){
     setVisible(true);
  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
  Wir ändern dazu den Konstruktor und entsprechend seinen Aufruf ab. Aber einen Erfolg haben wir erst, wenn wir den Konstruktor von JFrame einsetzten. Dazu müssen wir folgendes wissen: Unser Programm ist nicht nur eine Instanz (=Objekt) der Klasse HalloWelt, sondern auch der Klasse JFrame. Es wir dazu automatisch der Standardkonstruktor der Vaterklasse, in unserem Falle also JFrame() aufgerufen. Wir können den Aufruf dieses Konstruktors auch mit super() 'per Hand' machen, was offensichtlich wenig Sinn macht. Sinn macht es aber, wenn man einen anderen Konstruktor als den Standardkonstruktor der Vaterklasse aufrufen will. Da sich alle Kontruktoren einer Klasse allein in der Signatur, also in der Parameterliste unterscheiden, können wir diesen Aufruf ebenfalls mit super(...) realisieren und die Parameterliste entsprechend anpassen. So gibt es in der Klasse JFrame einen Konstruktor JFrame(String name), mit ihm kann man ein JFrame-Objekt erzeugen und ihm dabei einem Namen geben. Wir rufen diesen Konstruktor vom Konstruktor der Klasse HalloWelt aus mit super(name) auf. Jetzt verstehen wir auch, warum wir unseren Konstrukor der Klasse HalloWelt die Form  HalloWelt(String name) gegeben haben. Beim Aufruf von

new HalloWelt("Ich bin ein JFrame-Objekt");

übergeben wir das String-Objekt "Ich bin ein JFrame-Objekt" an den Konstruktor von HalloWelt und mit super wird es an den entsprechenden Konstruktor von JFrame weitergegeben.
 

Schritt 7
import javax.swing.*;
public class HalloWelt extends JFrame{
  public HalloWelt(String titel){
     super(titel);
     setVisible(true);
  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
 

Unser Objekt hat nun einen Namen, wie wir es von 'vernünftigen Windowsfenstern' gewohnt sind.

Wir können noch immer nicht zufrieden sein, denn wenn wir das Fenster durch Klicken auf das Kreuz in der rechten oberen Ecke schließen, verschwindet zwar das Fenster, aber das Programm läuft noch immer. Wir erkennen dies daran, dass der 'rote Punkte' in der Menüleiste des JavaEditors nicht verschwindet. Tatsächlich lässt sich das Programm auch nicht erneut starten. Dazu müssten wird das Programm durch Klicken auf roten Punkt beenden. Besser wäre ist es, wenn durch Anklicken des Kreuzes im Fensterrahmen nicht nur das Fenster verschwindet, sondern auch die Anwendung selbst beendet wird. Wie man das erreicht beschreibt der 8te Schritt.
 

Schritt 8
import javax.swing.*;
import java.awt.event.*;
public class HalloWelt extends JFrame{
  public HalloWelt(String titel){
     super(titel);
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     setVisible(true);
  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
  Für den Aufruf der Methode

setDefaultCloseOperation(EXIT_ON_CLOSE);

wird wieder keine Punktnotation verwendet, da sie geerbt von JFrame Methode unserer Klasse selbst ist.

Schritt 9
import javax.swing.*;
import java.awt.event.*;
public class HalloWelt extends JFrame{
  public HalloWelt(String titel){
     super(titel);
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     setSize(300, 300);
     setVisible(true);
     
  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
 

Die von JFrame geerbte Methode setSize(...) erlaubt es, dem Fenster die Größe zuzuweisen, mit der es beim Aufruf erscheint. Man kann es aber jeder Zeit noch verändern. Die in der Parameterliste der Methode setSize(...) durch Komma getrennte ganze Zahlen geben Breite und Höhe des Fensters in Pixel an. Sind beide Zahlen gleich, ist die Form des Fensters quadratisch. Spielen Sie mit diesen Zahlen. Welche Größe lässt sich mit dem ersten, welche mit dem zweiten Parameter steuern?
 

Schritt 10
import javax.swing.*;
import java.awt.event.*;
import java.awt.*;
public class HalloWelt extends JFrame{
  public HalloWelt(String titel){
     super(titel);
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     setSize(300, 300);
     Container cp = getContentPane(); 
     cp.setLayout(new BorderLayout());
     setVisible(true);
  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
  Im letzten Schritt schließlich sorgen wir dafür, dass das Fenster grafische Objekte wie Labels, Buttons, Zeichenflächen und ähnliches aufnehmen kann. Wir benutzen dazu einen Behälter (engl. container). Dieser Behälter bekommt noch ein Layout, in unserem Fall ein Borderlayout. Wie wir den Behälter benutzen werden wir bal erfahren.

Zunächst machen wir erst ein mal halt. Es drängt sich die Frage auf, ob man das alles, was wir in den 10 Schritten gesehen haben zum einen lernen, und zum zweiten jedes Mal neu eintippen müssen. Beides ist nicht nur unzumutbar sondern auch ineffizient.
 

Vorlagen Der JavaEditor stellt 4 verschieden Vorlagen zur Verfügung. Klicken wir auf die dritte Vorlage (JFrame) im Register Programm, so öffnet sich, nachdem man einen Namen für seine Anwendung ausgewählt  hat ein Programmrumpf, der gerade alle Elemente enthält, die wir in den Schritten 1 bis 10 kennen gelernt haben.
 
HalloWelt.java Wir wollen nun noch dafür sorgen, dass unser Programm den Namen "Hallo Welt" mit Recht trägt. Es soll also im Fenster der Schriftzug "Hallo Welt" erscheinen.  Dazu legen wir ein Label an, Versehen es mit dem entsprechenden Text und platzieren es in unserem Behälter.
 
Download:
HalloWelt.java
import javax.swing.*;
import java.awt.*;
public class HalloWelt extends JFrame{

  JLabel schriftZug;

  public HalloWelt(String titel){
     super(titel);
     setDefaultCloseOperation(EXIT_ON_CLOSE);
     setSize(300, 300);
     Container cp = getContentPane();
     cp.setLayout(new BorderLayout());
     
     schriftZug = new JLabel("HalloWelt");  
     cp.add(schriftZug,BorderLayout.NORTH);

     setVisible(true);

  }
  public static void main(String[] args){
     new HalloWelt("Ich bin ein JFrame-Objekt");
  }
}
zu 8.1.2 Aktionsabhorcher
zur Startseite www.pohlig.de  (C) MPohlig 2006