FANDOM


In diesem Abschnitt werden diverse AWT-Programme unterschiedlicher Komplexität schrittweise erklärt.

Kombinierte Elemente Bearbeiten

AllesLayoutPrntScr-0

Screenshot des Fensters

AllesLayoutSchema

Schema des Aufbaus

Dieses Programm soll ein ein einzelnes Fenster darstellen, welches alle Elemente, die im Hauptartikel beschrieben sind, enthält. Die Elemente werden mithilfe eines sogenannten GridLayouts auf dem Frame abgelegt.

Das Fenster basiert auf einem Frame, welcher einen Titel besitzt und mit dem Schließen-Button das Programm beendet. Auf dem Frame befindet sich ein Panel, welches mithilfe eines GridLayouts in insgesamt sechs Bereiche unterteilt ist. Diese Bereiche enthalten jeweils einen Button, ein Textfeld, ein Label, eine einzelne Checkbox sowie zwei weiter Checkboxen, die als Checkbox-Gruppe zusammengefasst sind.

Der Frame Bearbeiten

Der Frame erhält, da er später als Objekt verwendet wird, eine eigene Klasse. Diese erbt von "java.awt.Frame". Der Titel des Frames wird durch den Konstruktor aus der Main an die Klasse übergeben. Der Konstruktor dieser Klasse übernimmt den Konstruktor von java.awt.Frame mithilfe eines "super()"-Befehls. Des weiteren benötigt die Klasse einen Listener, damit durch das anklicken des Schließen-Buttons das Programm beendet wird. Dieser befindet sich wiederum in einer eigenen Klasse, die ihrerseits von "java.awt.event.WindowAdapter" erbt. In der Listener-Klasse wird nun eine Methode durch einen "System.exit()"-Befehl erweitert und dadurch überschrieben.

Die Frame-Klasse Bearbeiten

Diese Klasse darf einen beliebigen Namen außer "Frame" besitzen, da ansonsten ein schwerer Fehler entsteht. In diesem Beispiel hat die Klasse den Namen "Rahmen". Wenn nun ein entsprechendes Objekt erstellt wird, ist dieses ein Frame-Objekt vom Typ "Rahmen" und Typ "Frame".

import java.awt.Frame;

class Rahmen extends Frame
{
	Rahmen(String titel)		 
	{
		super(titel);		
		addWindowListener(new Listener());		
	}
}

Der Konstruktor erwartet den String "titel". Dieser wird ihm aus der Main übergeben. Dies ist allerdings optional, es ist auch folgendermaßen möglich:

import java.awt.Frame;

class Rahmen extends Frame
{
	static String titel = "titel";
	Rahmen()		
	{
		super(titel);
		addWindowListener(new Listener());	
	}
}

Hierbei ist das "static"-Attribut des Strings wichtig. Die Methode "addWindowListener()" erwartet ein Objekt vom Typ "windowAdapter". Da dieses Objekt die Eigenschaft haben soll, am Ende durch einen Button das Programm beenden zu können, wird hierzu eine eigene Klasse erstellt.

Die Listener-Klasse Bearbeiten

Die Listener-Klasse erbt von "java.awt.event.WindowAdapter". Die in diesem Fall relevante Methode ist "windowClosing()" vom Typ "void", welche ein "WindowEvent" erwartet. Diese Methode wird in der Listener-Klasse mit einem "System.exit()"-Befehl überschrieben.

import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

class Listener extends WindowAdapter
{
	@Override
	public void windowClosing(WindowEvent e) 
	{
		System.exit(0);
	}
}

Das Panel Bearbeiten

Ähnlich der Frame, ist das Panel ein eigenes Objekt vom Typ "java.awt.Panel". Darauf werden später die einzelnen Elemente abgelegt. Dazu wird auch hier eine eigene Klasse erstellt, die von "java.awt.Panel" erbt. Normalerweise werden bereits in dieser Klasse die einzelnen Elemente deklariert. Im Konstruktor werden diese schließlich "zusammengesetzt". Auch hier darf die Klasse selbst nicht "Panel" heißen, also wurde der Name zu "Basis" abgeändert.

import java.awt.Panel;

class Basis extends Panel 
{
	/*Hier werden später die 
          einzelenen Elemente 
	  deklariert*/
	
	Basis()
	{
		/*hier werden diese
                  weiter konfiguriert
                  und zusammengesetzt*/
        }
}

Die Main Bearbeiten

In der main-Methode werden das Frame- und das Panel-Objekt erstellt ausgeführt. Alles weitere wird in den Konstruktoren der jeweiligen Objekte geregelt.

public class Main 
{
	public static void main(String[] args) 
	{
		Rahmen Fenster = new Rahmen();
		Fenster.add(new Basis());
		Fenster.pack();
		Fenster.setVisible(true);
	}

}
}

Es wird das Objekt "Fenster" vom Typ "Rahmen" erstellt. diesem wird ein neues Objekt vom Typ "Basis" hinzugefügt. Dies bedeutet, dass das Panel auf den Frame "gelegt" wurde. mit der "pack()"-Methode wird die Größe des Fensters automatisch auf dessen Inhalt angepasst. In der letzten Zeile wird das Fenster sichtbar gemacht. Wenn die Frame-Klasse im Konstruktor einen String als Titel erwartet, muss der Ausdruck wie folgt lauten.

Rahmen Fenster = new Rahmen("Titel");

Die Elemente Bearbeiten

Die Elemente des Fensters werden, wie bereits erwähnt, in der Panel-Klasse deklariert. In diesem Fall werden ein Button, ein Textfeld, ein Label, eine Chekbox und eine CheckboxGroup, bestehend aus zwei Checkboxen erstellt. Des weiteren wird ein sogenanntes GridLayout erstellt, welches dem Panel zugewiesen wird, um entsprechend viele Elemente ablegen zu können.

import java.awt.*;

class Basis extends Panel 
{
	Button Button1 = new Button("Button");
	TextField TextField1 = new TextField();
	Label Label1 = new Label("Label");
	Checkbox Checkbox1 = new Checkbox("Checkbox 1", false);
	
	CheckboxGroup CB1 = new CheckboxGroup();
	Checkbox CB1_Checkbox1 = new Checkbox("Checkbox-", CB1, false);
	Checkbox CB1_Checkbox2 = new Checkbox("-Group", CB1, false);
	
	GridLayout Layout1 = new GridLayout(2,3);
	
	Basis()
	{

	}
}

Es werden alle erwähnten Objekte in absteigender Reihenfolge erstellt. Der Konstruktor der Button-, TextField-, Label- und Checkbox-Klassen erwartet einen String für die jeweilige Beschriftung, kann aber auch leer gelassen werden. Der Checkbox kann zusätzlich noch einen boolean-Zustand sowie die Zuweisung einer CheckboxGroup übergeben werden. Der Konstruktor des GridLayouts erwartet die Anzahl an Zeilen und Spalten in Form von int-Werten. Da insgesamt sechs Elemente abgelegt werden sollen, besitzt das Layout in diesem Fall 2 Zeilen und 3 Spalten.

Der Panel-Konstruktor Bearbeiten

Wie bereits erwähnt, werden nun jene Elemente im Konstruktor dieser Klasse zusammengefügt.

Basis()
{
	setLayout(FrameLayout);

	add(Button1);
	add(TextField1);
	add(Label1);
		
	add(Checkbox1);
	add(CB1_Checkbox1);
	add(CB1_Checkbox2);
}

Der erste Befehl definiert das Layout für das Panel. anschließend werden chronologisch alle Elemente hinzugefügt.

Der Quellcode des Gesamten Programms: http://pastebin.com/L9bQY8s2

Kommunizierende Fenster Bearbeiten

Sourcecode: http://pastebin.com/eVpgiprA

KommFensterPrntScr

Screenshot der Fenster

Dieses Beispiel enthält insgesamt drei (bis auf den Titel) identisch aussehende Fenster. Mit dem Start des Programms öffnet sich lediglich eines dieser Fenster. Mit einem entsprechenden Button können weitere Fenster des gleichen Typs hinzugefügt werden, allerdings nicht mehr als drei. Mit einem weiteren Button lässt sich das jeweilige Fenster schließen. Mit dem Klassischen Schließen-Menü (Alt+F4) wird das Programm beendet.

KommFensterSchema

Schematischer Aufbau

Es besteht die Möglichkeit, einen Text in ein Textfeld einzugeben und diesen durch Bestätigung eines Buttons in einer beliebigen Kombination aller Fenster auszugeben. Die Selektion der Fenster geschieht über drei Checkboxen.

Des weiteren ist es möglich, eine von insgesamt drei Farben auszuwählen und diese, ebenso wie den Text, in einer beliebigen Kombination der Fenster anzeigen zu lassen. Dafür werden die gleichen Checkboxen genutzt, die für die Ausgabe des Textes verwendet wurden. Die Wahl der Farben selbst erfolgt über eine Checkbox-Gruppe.

Klassen-Struktur Bearbeiten

Standardmäßig existiert immer eine eigene Klasse, in der die Main-Methode enthalten ist. Daneben braucht auch dieses Programm eine je Fenster eine "Rahmen"-Klasse, die von "Frame" erbt, eine "Basis"-Klasse, die von "Panel" erbt und eine "Listener"-Klasse, die aber nur einmal benötigt wird, da beim Schließen über den Frame in jedem Fall das Programm beendet wird.
Java AWT Tutorial - Kommunizierende Fenster

Java AWT Tutorial - Kommunizierende Fenster

Video Tutorial

Demnach sieht das Setup folgendermaßen aus:
  • Main.java
  • Listener.java
  • Rahmen_01.java
  • Rahmen_02.java
  • Rahmen_03.java
  • Basis_01.java
  • Basis_02.java
  • Basis_03.java

Die Listener-Klasse kann 1:1 vom oberen Programm übernommen werden. Die Rahmen-Klassen sind auch identisch, es müssen lediglich drei mit unterschiedlichem Namen erstellt werden.Die Basis-Klassen sind vom grundsätzlichen Aufbau gleich, allerdings stark modifiziert. Wichtig ist auch, dass sich all diese Klassen im selben Package befinden.

Die Main Bearbeiten

package wiki.communicating.windows;

public class Main 
{
	static Rahmen_01 Fenster1 = new Rahmen_01("Fenster 1");
	static Rahmen_02 Fenster2 = new Rahmen_02("Fenster 2");
	static Rahmen_03 Fenster3 = new Rahmen_03("Fenster 3");
	
	static Basis_01 Panel1 = new Basis_01();
	static Basis_02 Panel2 = new Basis_02();
	static Basis_03 Panel3 = new Basis_03();
	
	static boolean Fenster1active = false;
	static boolean Fenster2active = false;
	static boolean Fenster3active = false;
	
	static int TotalWindowsDisplayed = 0;
	
	public static void main(String[] args) 
	{
		Fenster1.add(Panel1);
		Fenster1.pack();
		Fenster1.setVisible(true);
		TotalWindowsDisplayed ++;
		Fenster1active = true;
	}

}
In diesem Fall werden sowohl die Objekte des Typs "Rahmen", also die Frames außerhalb der main-Methode, sowie die Objekte des Typs "Basis", also die Panels deklariert. Dies erleichtert später den Zugriff aus den anderen Klassen heraus. Die Boolean-Werte "Fenster(1-3)active" erhalten je nachdem, ob das jeweilige Fenster gerade geöffnet oder geschlossen ist, einen "true" oder "false"-Wert. Somit lässt sich zu jeder Zeit abfragen, ob das jeweilige Fenster aktiv ist. Das ist notwendig, dass nicht aus Versehen mehrere gleiche Fenster geöffnet werden. Der int-Wert "TotalWindowsDisplayed" zeigt an, wie viele Fenster insgesamt offen sind. Das ist wiederum wichtig, da maximal 3 Fenster gleichzeitig geöffnet sein dürfen. In der main-Methode wird dann das erste Fenster geöffnet und die jeweiligen Hilfsvariablen aktualisiert.

Die Basis-Klasse Bearbeiten

In dieser Klasse werden, wie bereits beschrieben, alle einzelnen Elemente und Layouts erstellt und zusammengesetzt. Es werden insgesamt 2 Layouts benötigt.

package wiki.communicating.windows;

import java.awt.*;
import java.awt.event.*;

class Basis_01 extends Panel{
	
	private GridLayout LayoutB1 = new GridLayout(4,3);
	private GridLayout LayoutColorChoice = new GridLayout(1,3);

        private Panel PanelColorChoice = new Panel();

(...)
Das erste Layout ist das, auf welchem alle anderen Elemente abgelegt werden. Wie auf dem Schema zu erkennen ist, wird auf diesem Layout an der Position (2,2) ein weiteres Panel ("PanelColorChoice") platziert, dem wiederum ein Layout zugewiesen wird. Auf diesem Layout werden die Checkboxen zur Farbwahl abgelegt. Alle Elemente, auf die nicht aus einer anderen Klasse zugegriffen wird, erhalten das Attribut "private", da sie in den verschiedenen "Basis"-Klassen unter gleichem Name vorkommen werden und dies sonst zu Problemen führen könnte.
(...)

static Label ColorOutput = new Label();
static Label TextOutput = new Label();
	
private Button ApplyColor = new Button("Einfaerben");
private Button ApplyText = new Button("Text setzen");
	
private TextField TextInput = new TextField();
	
private CheckboxGroup ColorChoice = new CheckboxGroup();
private Checkbox ColorChoiceRed = new Checkbox("ROT", ColorChoice, false);
private Checkbox ColorChoiceGreen = new Checkbox("GRUEN", ColorChoice, false);
private Checkbox ColorChoiceBlue = new Checkbox("BLAU", ColorChoice, false);
	
private Checkbox WindowChoice1 = new Checkbox("Fenster 1", false);
private Checkbox WindowChoice2 = new Checkbox("Fenster 2", false);
private Checkbox WindowChoice3 = new Checkbox("Fenster 3", false);
	
private Button AddWindow = new Button("Fenster Hinzufuegen");
private Button RemoveWindow = new Button("Fenster Schliessen");

private Label EmptySpace = new Label();

(...)
Die beiden Label "TextOutput" und "ColorOutput" (jeweils auf Position (1,3) und (2,3) des Schemas) sind statisch und innerhalb des Packages aufrufbar. Dies ist wichtig, da man z.B. die Farbe in einem Fenster wählt und diese im anderen geändert werden muss. In diesem Fall wird aus der "Basis"-Klasse des einen Fensters auf die "Basis"-Klasse des Anderen zugegriffen. Alle anderen Elemente sind aus oben genannten Gründen "private".

Der Konstruktor Bearbeiten

Im Konstruktor wird das gesamte Fenster nun "zusammengebaut". Hierbei gilt wie immer, das die Elemente von links nach rechts, dann von oben nach unten nacheinander auf das Layout gesetzt werden.

(...)

Basis_01()
{
	setLayout(LayoutB1);
		
	add(ApplyText);
	add(TextInput);
	add(TextOutput);
	add(ApplyColor);

	add(PanelColorChoice);
	PanelColorChoice.setLayout(LayoutColorChoice);
	PanelColorChoice.add(ColorChoiceRed);
	PanelColorChoice.add(ColorChoiceGreen);
	PanelColorChoice.add(ColorChoiceBlue);
		
	add(ColorOutput);
		
	add(WindowChoice1);
	add(WindowChoice2);
	add(WindowChoice3);
		
	add(AddWindow);
	add(RemoveWindow);
	add(EmptySpace);

(...)
"LayoutB1" ist das 3x4-große GridLayout, welches zuerst definiert wird. An der Position (2,2) wird nun ein weiteres Panel abgelegt. Diesem wird das 1x3-große Layout "LayoutColorChoice" zugewiesen. Auf diesem werden dann die Checkboxen für die Auswahl der Farbe abgelegt. Anschließend werden die restlichen Elemente hinzugefügt.

Im nächsten Schritt werden die insgesamt vier Buttons "ApplyText", "ApplyColor", "RemoveWindow" und "AddWindow" mit Listenern ausgestattet.

(...)

        ApplyText.addActionListener(new ApplyTextListener());
	AddWindow.addActionListener(new OpenWindowListener());
	RemoveWindow.addActionListener(new CloseWindowListener());
	ApplyColor.addActionListener(new ApplyColorListener());
}

Damit ist auch der Konstruktor fertig. Die jeweiligen Listener ("ApplyTextListener" , etc.) sind Objekte, welche alle eigene Klassen besitzen. Diese werden innerhalb der Klasse "Basis_01" erstellt.

Der ApplyTextListener Bearbeiten

Jeder ActionListener eines AWT-Buttons besitzt eine eigene Methode, die ausgeführt wird, sobald der entsprechende Button gedrückt wird. Der "ApplyTextListener" muss zwei Sachen können; Zum einen muss er abfragen, welche Checkbox aktiviert wurde, um den eingegeben Text auf den richtigen Fenstern anzuzeigen, und zum anderen muss er den eingegebenen Text in den entsprechenden Fenstern anzeigen.

private class ApplyTextListener implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		if(WindowChoice1.getState() == true)
			Basis_01.TextOutput.setText(TextInput.getText());
			
		if(WindowChoice2.getState() == true)
			Basis_02.TextOutput.setText(TextInput.getText());
			
		if(WindowChoice3.getState() == true)
			Basis_03.TextOutput.setText(TextInput.getText());
	}	
	
}
Insgesamt werden hier drei If-Abfragen nacheinander abgearbeitet. Der Ausdruck "WindowChoice1.getState()" gibt den momentanen Boolean-Status der ersten Checkbox zurück. Wenn der Wert hier "false" beträgt, ist die Checkbox nicht ausgewählt und das If-Statement wird nicht abgearbeitet. Andernfalls schon. In jenem Fall wird zunächst das "TextOutput"-Objekt der jeweiligen Klasse aufgerufen. Da es sich hier um ein statisches Objekt handelt und in jeder Klasse unter dem gleichen Namen deklariert wurde, lautet der Aufruf "Basis_(#).TextOutput". Da man nun den Text verändert will, hängt man die Methode ".setText()" an. Innerhalb der Klammer wird dieser Text erwartet. Da sich der Text im "TextInput"-Textfeld befindet, wird dieses Objekt aufgerufen und mit der Methode ".getText()" der Text zurückgegeben. Dies wird in drei voneinander unabhängigen If-Statements für jedes Fenster wiederholt.

Der ApplyColorListener Bearbeiten

Dieser Listener funktioniert auf die gleiche Art und Weise, außer dass hier ein weiterer Zwischenschritt notwendig ist, da nicht nur die Auswahl der Fenster abgefragt werden muss, sondern auch die Farbwahl. Demnach wird zunächst eine If-Abfrage gestartet, um herauszufinden, welche Farbe ausgewählt ist. Wenn die ausgewählte Farbe gefunden wurde, starten, ähnlich wie beim ApplyTextListener, drei weitere If-Statements, die, je nach Auswahl des Fensters, das ColorOutput-Objekt entsprechend einfärben.

private class ApplyColorListener implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent e)
	{
		if(ColorChoiceRed.getState() == true)
		{
			if(WindowChoice1.getState() == true)
				Basis_01.ColorOutput.setBackground(Color.RED);			
			if(WindowChoice2.getState() == true)
				Basis_02.ColorOutput.setBackground(Color.RED);	
			if(WindowChoice3.getState() == true)
				Basis_03.ColorOutput.setBackground(Color.RED);	
		}
		else if(ColorChoiceGreen.getState() == true)
		{
			if(WindowChoice1.getState() == true)
				Basis_01.ColorOutput.setBackground(Color.GREEN);			
			if(WindowChoice2.getState() == true)
				Basis_02.ColorOutput.setBackground(Color.GREEN);	
			if(WindowChoice3.getState() == true)
				Basis_03.ColorOutput.setBackground(Color.GREEN);	
		}
		else if(ColorChoiceBlue.getState() == true)
		{
			if(WindowChoice1.getState() == true)
				Basis_01.ColorOutput.setBackground(Color.GREEN);			
			if(WindowChoice2.getState() == true)
				Basis_02.ColorOutput.setBackground(Color.GREEN);	
			if(WindowChoice3.getState() == true)
				Basis_03.ColorOutput.setBackground(Color.GREEN);	
		}
	}
}

Der CloseWindow Listener Bearbeiten

Der CloseWindow Listener soll in diesem Fall nicht das Programm beenden (wie es der WindowAdapter der Frame-Klassen tun würde), sondern ledigleich das jeweilige Fenster schließen. Da die Frames in der Main-Klasse als statische Objekte deklariert sind, werden diese aus der Listener-Methode aufgerufen.

private class CloseWindowListener implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		Main.Fenster1.dispose();
                Main.Panel1.setEnabled(false)
		Main.Fenster1.removeAll();
		Main.Fenster1active = false;
		Main.TotalWindowsDisplayed --;
	}
}
Die ".dispose()"-Methode schließt den Frame. Das Panel wird deaktiviert, damit es, während das Fenster geschlossen ist, nicht verändert werden kann. Die ".removeAll()"-Methode entfernt alle Elemente, die auf dem Frame abgelegt waren. Damit wird der Frame, der selbst als statisches Objekt weiterhin aktiv bleibt, "geräumt". Falls das Fenster nun wirder geöffnet werden soll, kann der Frame wieder sichtbar gemacht und ein neues Panel darauf abgelegt werden.

Die statische Variable Fenster1active wird auf "false" gesetzt, da nun das Fenster nicht mehr aktiv ist. TotalWindowsDisplayed wird um einen Wert verringert, da insgesamt ein Fenster weniger angezeigt wird.

Der OpenWindow Listener Bearbeiten

Der OpenWindow Listener muss insgesamt drei Aufgaben übernehmen. Zum einen muss abgefragt werden, ob die maximale Anzahl an Fenstern bereits erreicht ist (und in diesem Fall kein weiteres Fenster mehr öffnen), daraufhin muss entschieden werden, welches Fenster exakt geöffnet wird, um keines doppelt zu öffnen und letztendlich soll das Fenster geöffnet werden. Zuletzt wird dann noch das Panel aktiviert, für den Fall, dass es beim letztn Schließen des Fensters deaktiviert wurde

private class OpenWindowListener implements ActionListener
{
	@Override
	public void actionPerformed(ActionEvent e) 
	{
		if(Main.TotalWindowsDisplayed == 3)System.out.println("");
		else if(Main.Fenster2active == false)
		{
			Main.Fenster2.add(Main.Panel2);
			Main.Fenster2.pack();
			Main.Fenster2.setVisible(true);
			Main.TotalWindowsDisplayed ++;
			Main.Fenster2active = true;
			Main.Panel2.setEnabled(true);
		}
		else if(Main.Fenster3active == false)
		{
			Main.Fenster3.add(Main.Panel3);
			Main.Fenster3.pack();
			Main.Fenster3.setVisible(true);
			Main.TotalWindowsDisplayed ++;
			Main.Fenster3active = true;
			Main.Panel3.setEnabled(true);
		}
	}
}
Hier wird in einem dreiteiligen if-Statement zuerst abgefragt, ob alle drei Fenster geöffnet sind. Falls dies der Fall ist, endet die Abfrage vorzeitig und es geschieht nichts. ansonsten wird abgefragt, ob "Fenster3" oder "Fenster2" noch aktiv sind. Im jeweiligen Fall wird das jeweils andere Fenster geöffnet. Sind beide Fenster geschlossen, wird zuerst "Fenster2", dann "Fenster3" geöffnet. Das endgültige Öffnen des Fensters geschieht auf gleiche Weise wie in der main-Methode.

Basis_02 und Basis_03 Bearbeiten

Alles oben beschriebene wird, da alle Fenster im Endeffekt die gleiche Funktion haben sollen, auch in den Basis_02- und Basis_03-Klassen übernommen. Es muss allerdings darauf geachtet werden, dass die korrekten Fenster angesprochen werden. So muss die Methode des CloseWindow Listener in "Basis_03" folgendermaßen aussehen.

public void actionPerformed(ActionEvent e) 
{
       Main.Fenster3.removeAll();
       Main.Panel3.setEnabled(false);
       Main.Fenster3.dispose();
       Main.Fenster3active = false;
       Main.TotalWindowsDisplayed --;
}