Dazu werden wir eine JMenuBar aus der Swing-Bibliothek von Java verwenden und das Menü mit Einträgen füllen. Damit die Menüeinträge auf Benutzereingaben reagieren, werden wir ihnen einen ActionListener hinzufügen.
Den Listener implementieren wir in Form einer anonymen inneren Klasse. Was das genau ist werden wir weiter unten ausführlich erklären.
Weiterhin möchten wir, dass unser Java Spiel auch auf Fensterereignisse reagiert. Dazu registrieren wir einen WindowListener für unser Spielfenster. Mit diesem Listener können wir unser Java Programm reagieren lassen, wenn das Spielfenster bspw. vom Benutzer geschlossen wird.
Am Ende dieser Lektion werden wir ein funktionstüchtiges Spielfenster, das ein Menü besitzt und auf Benutzereingaben reagiert, programmiert und somit die Grundlage für die grafische Darstellung unseres Java Spiels geschaffen haben.
In dieser Lektion lernt ihr:
- Paket des Java Projekts umbenennen
- Neue Klasse mit NetBeans erstellen
- Spielfenster erstellen und anzeigen
- Ein Menü für das Spielfenster erstellen
- Einen ActionListener für den Menüeintrag registrieren
- Einen WindowListener für unser Spielfenster registrieren
Lektionen des Java Tutorials:
- Java Spiel Programmieren Tutorial
- Teil 1 – Java Projekt erstellen
- Teil 2 – Spielfenster erstellen
- Teil 3 – Spielfläche erstellen
- Teil 4 – Spielobjekte erstellen
- Teil 5 – Panzer und Spielsteuerung
- Teil 6 – Gegnerische Panzer erstellen
- Teil 7 – Die Spiellogik implementieren
- Teil 8 – Einstellungsdialog erstellen
Andere hilfreiche Beiträge:
Nun wünschen wir euch viel Spaß beim zweiten Teil unseres Java Spiel Programmieren Tutorials. Los geht’s!
1. Das Paket unseres Java Projekts umbenennen
Bevor wir mit der Programmierung des Spielfensters beginnen, nehmen wir noch eine kleine Änderung an unserem Java Projekt vor. Wir werden den Namen unseres Packages ändern.
Pakete (Packages) sind in Java von großer Bedeutung. Paketname und Klassenname zusammen identifizieren eine Klasse in Java eindeutig.
Der Name einer Klasse ohne die Paketnennung wird als unqualifizierter Klassenname bezeichnet. In unserem Projekt wäre das bspw. der Klassenname PanzerHQ.
Wird die Klasse zusammen mit dem Paketnamen angegeben, spricht man vom vollqualifizierten Klassennamen in Java. Momentan wäre der vollqualifizierte Name unserer Hauptklasse panzerhq.PanzerHQ.
Wir möchten nun den Namen unseres Pakets in de.programmierenlernenhq.panzerhq
abändern. Indem wir die eigene Webadresse als Paketnamen verwenden, erreichen wir eine weltweite Eindeutigkeit unseres Java Projekts. Dazu wird die URL rückwärts geschrieben.
Der Paketname (Packagename) wird unmittelbar vor der Klassendefinition mit dem Schlüsselwort package definiert. Er legt wir Paketzugehörigkeit der anschließend definierten Klasse fest.
Mit folgenden Arbeitsschritten ändern wir den Paketnamen unseres Java Projekts:
- Mit der rechten Maustaste auf den Paketnamen
panzerhq
in der linken Projektleiste klicken. - Anschließend auf den
Refactor
-Eintrag im Kontextmenü klicken. - Und schließlich auf
Rename...
klicken, um den Umbenennen Dialog zu öffnen.
Nun öffnet sich ein neuer Dialog, der uns beim Umbenennen unseres Projektpakets hilft.
Wir geben als neuen Paketnamen in das Textfeld New Name de.programmierenlernenhq.panzerhq
ein und klicken anschließend auf den Refactor
-Button.
Jetzt führt die NetBeans IDE automatisch das Refactoring durch und ändert den Paketnamen unseres Java Projekts. Als Ergebnis sollte euer Projekt nun wie folgt in NetBeans aussehen:
Wie in der oberen Abbildung zu sehen ist, wurde das Projektpaket (A)und auch die Paketdefinition (B) in unserer Klasse PanzerHQ von NetBeans umbenannt. Somit sind wir startklar für die Programmierung des Spielfensters für unser Java Spiel.
2. Eine neue Klasse mit der NetBeans IDE erstellen
Unser Java Spiel soll in einem eigenen Fenster ausgeführt werden. Dieses Fenster bezeichnen wir als Spielfenster (GameWindow) und soll durch eine eigenen Java Klasse repräsentiert werden.
Dazu erstellen wir nun eine neue Java Klasse mit dem Namen GameWindow. Die neue Klasse wird die Eigenschaften der Klasse JFrame aus dem Paket javax.swing erben.
Die JFrame-Klasse können wir uns als Fensterrahmen vorstellen, dem wir grafische Komponenten hinzufügen.
Alle grafischen Komponenten der Swing-Bibliothek erben von der Klasse JComponent, sogar die Klasse JFrame selbst. Somit könnte man sogar ein JFrame-Objekt unserem JFrame hinzufügen, da auch dieses nur eine grafische Komponente in Java ist.
Soviel als kurze Einleitung in das Thema Grafische Darstellung in Java. Kommen wir nun zurück zu unserem Java Spiel, welchem wir nun ein eigenes Spielfenster spendieren.
Dazu erstellen wir die Klasse GameWindow wie folgt:
- Wir klicken mit der rechten Maustaste auf den Packagenamen in der Projektleiste.
- Danach auf den
New
-Eintrag im Kontextmenü klicken. - Anschließend auf den Eintrag
Java Class...
klicken.
Daraufhin öffnet sich der New Java Class-Dialog von NetBeans. In diesem Dialog geben wir als Namen der zu erstellenden Klasse GameWindow
ein.
Alle anderen Einstellungen lassen wir unverändert und bestätigen den Dialog mit einem Klick auf Finish
.
Jetzt generiert NetBeans eine neue Java-Datei mit dem Namen GameWindow.java
und fügt sie in das Paket unseres Projekts ein. Dies sollte bei euch wie folgt aussehen:
Bisher macht unsere neue Klasse GameWindow noch gar nichts. Das werden wir nun ändern und ihr eine grafische Komponente hinzufügen.
3. Das Spielfenster erstellen und anzeigen lassen
Bei der grafischen Komponente handelt es sich in unserem Fall um ein JPanel-Objekt, das wir für unser Java Spiel als Zeichenbrett verwenden, auf dem wir unsere Panzer und auch sämtliche anderen grafischen Spielelemente zeichnen (paint) werden.
Wir ersetzten nun den Quellcode der Datei GameWindow.java
mit folgenden Code:
GameWindow.java
package de.programmierenlernenhq.panzerhq; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; public class GameWindow extends JFrame{ public GameWindow() { JPanel testPanel = new JPanel(); testPanel.setPreferredSize(new Dimension(600, 400)); add(testPanel); pack(); setTitle("PanzerHQ"); setLocation(10, 10); setResizable(false); setVisible(true); } }
Falls ihr ein anderen Paketnamen gewählt habt, müsst ihr die erste Zeile entsprechend anpassen.
Mit der Anweisung in Zeile 11 erzeugen wir ein neues JPanel-Objekt. Anschließend setzen wir in Zeile 12 die bevorzugte Größe dieser grafischen Komponente auf 600 x 400 Pixel.
In Zeile 14 fügen wir unserem JFrame das JPanel-Objekt testPanel
hinzu. Mit der nachfolgenden Anweisung pack() sorgen wir dafür, dass die hinzugefügte grafische Komponente korrekt dargestellt wird.
Die Methode pack() bewirkt, dass unser Spielfenster seine ideale Größe berechnet. Dazu kontrolliert es die preferredSize-Werte seiner inneren Komponenten. Unser Spielfenster, der JFrame, besitzt nur das JPanel-Objekt als innere Komponente. Den preferredSize-Wert des JPanel haben wir mit 600 x 400 Pixel vorgegeben.
Mit den Anweisungen in den Zeilen 17 bis 19 legen wir einen Titel für unser Spielfenster fest, geben die absolute Position der linken oberen Fensterecke vor und sorgen dafür, dass die Größe des Spielfensters nicht vom Benutzer verändert werden kann.
Mit der letzten Anweisung in Zeile 21 lassen wir unser Spielfenster anzeigen.
In NetBeans sollte die Klassendatei GameWindow.java
nun wie folgt aussehen:
In der oberen Abbildung sind die Import-Anweisungen (A) und der Konstruktor (B) unserer GameWindow-Klasse mit einem blauen Rahmen markiert.
Es ist nun an der Zeit unser Spielfenster das erste Mal zu testen. Dazu werden wir im nächsten Unterabschnitt unser Java Projekt von der NetBeans IDE ausführen lassen.
3.1 Starten unseres Java Projekts und Testen des Spielfensters
Um unser Spielfenster testen zu können, müssen wir eine Instanz der Klasse GameWindow erzeugen. Das Instanziieren unseres Spielfenster muss an einer ganz bestimmten Stelle in unserem Java Projekt erfolgen, nämlich in der main() Methode unserer Hauptklasse PanzerHQ.
Jedes Java Programm muss eine statische Methode main(String[] args) besitzen. Die main() Methode ist der Einstiegspunkt in Java Anwendungen. Beim Starten einer Java Anwendung lädt der Java Interpreter das im Aufruf angegebene Klassenobjekt und sucht nach einer statischen Methode mit der folgenden Signatur:
public static void main (String[] args)
Kann der Java-Interpreter die main() Methode nicht finden, führt dies zu einem Laufzeitfehler und es wird eine Fehlermeldung ausgegeben. Wird die main() Methode gefunden, erstellt der Java Interpreter ein Array mit den Kommandozeilenparametern und übergibt das Array als Argument an die main() Methode.
Wir wollen nun eine Instanz unseres Spielfensters erzeugen.
3.1.1 Das Spielfenster unseres Java Spiels instanziieren
Wir öffnen die Datei PanzerHQ.java
unserer Hauptklasse im Editorfenster von NetBeans und fügen die folgende markierte Zeile in ihre main() Methode ein:
PanzerHQ.java
package de.programmierenlernenhq.panzerhq; public class PanzerHQ { public static void main(String[] args) { new GameWindow(); } }
Mit der Anweisung in Zeile 7 erzeugen wir ein GameWindow-Objekt. Dieses Objekt ist eine Instanz der Klasse GameWindow. Somit haben wir unser Spielfenster instanziiert.
In NetBeans sollte die Klasse PanzerHQ
jetzt wie folgt aussehen:
In der oberen Abbildung ist die einzufügende Zeile blau unterstrichen und mit einem A markiert worden.
3.1.2 Ausführen unseres Java Projekts in NetBeans
Jetzt sind wir bereit unser Java Projekt auszuführen und uns das Spielfenster anzeigen zu lassen. Dazu klicken wir mit einem Linksklick auf das grüne Run Project
-Symbol in der oberen Symbolleiste.
Anschließend startet die NetBeans IDE unser Projekt und führt die main() Methode unserer Hauptklasse PanzerHQ aus, in der wir das Spielfenster erzeugen lassen. Das Spielfenster ist ein Objekt vom Datentyp GameWindow, den wir selbst definiert haben.
Das Spielfenster sorgt selbst dafür, dass es sichtbar wird (mit der Anweisung setVisible(true) im Konstruktor) und in den Vordergrund rückt. Es wird an der absoluten Bildschirmposition (10, 10) angeordnet und trägt den Fenstertitel „PanzerHQ“.
In der folgenden Abbildung ist unser Spielfenster in der ersten Version zu sehen. Es besteht momentan nur aus einem grauen JPanel (Zeichenbrett), auf dem wir später unsere Spielobjekt zeichnen lassen werden:
Wir haben unseren ersten Erfolg zu vermelden. Das Fenster, in dem unser Java Spiel ausgeführt werden soll, wird auf unserem Computerbildschirm angezeigt.
Jetzt ist es an der Zeit dem Spielfenster eine Menüleiste (Menu Bar) hinzuzufügen. Dies werden wir im nächsten Abschnitt vornehmen.
4. Ein Menü für das Spielfenster erstellen und mit Einträgen füllen
Unser Java Spiel wird über eine eigene Menüleiste verfügen. Über die Menüleiste wird es später u.a. möglich sein das Java Spiel zu pausieren, wieder fortzusetzen und neu zu starten. Um die Menüleiste für unser Spielfenster zu realisieren, werden wir uns der Klasse JMenuBar bedienen.
Ein Objekt dieser Klasse kann dem Fenster (JFrame) als Menüleisteninstanz mit der Methode setMenuBar() zugefügt werden. Wie alle grafischen Komponenten der Swing-Bibliothek ist auch die JMenuBar von der Klasse JComponent abgeleitet, wodurch sie über eine Methode add() verfügt, mit deren Hilfe wir der Menüleiste ihre Einträge zuweisen können.
Um die Menüleiste unserem Spielfenster GameWindow hinzuzufügen, gehen wir wie folgt vor:
- Einfügen der benötigten Import-Anweisungen in die Klasse GameWindow.
- Definieren der Methoden createMenu() und addFileMenuItems().
- Aufrufen der Methode createMenu() im Konstruktor der GameWindow-Klasse.
Anschließend werden wir unser Java Projekt ausführen und die Menüleiste unseres Spielfensters testen.
4.1 Einfügen der Import-Anweisungen
Wir öffnen die GameWindow-Klasse im Editor von NetBeans und fügen den folgenden Quellcode unter die bereits vorhanden Import-Anweisungen ein:
GameWindow.java
import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem;
Als Nächstes werden wir zwei neue Methoden erstellen, mit deren Hilfe wir die Menüleiste erzeugen und sie mit Menüeinträgen füllen.
4.2 Definieren der Methoden createMenu und addFileMenuItems
Wir werden nun die beiden Methoden createMenu() und addFileMenuItems() in unserer GameWindow-Klasse definieren. Dazu fügen wir die folgenden beiden Methodendefinitionen direkt nach dem Konstruktor der GameWindow-Klasse ein:
GameWindow.java
private void createMenu() { JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); JMenu gameMenu = new JMenu("Game"); JMenu prefMenu = new JMenu("Preferences"); menuBar.add(fileMenu); menuBar.add(gameMenu); menuBar.add(prefMenu); addFileMenuItems(fileMenu); } private void addFileMenuItems(JMenu fileMenu) { JMenuItem quitItem = new JMenuItem("Quit"); fileMenu.add(quitItem); }
Diese beiden Methoden erstellen zusammen die Menüleiste unseres Spielfensters. Mit der ersten Methode createMenu() erzeugen wir die Menüleiste und fügen ihr drei Menüs hinzu. Mit der zweiten Methode addFileMenuItems() fügen wir einem der drei erstellten Menüs, dem File-Menü, einen Menüeintrag hinzu.
Das Erstellen der Menüleiste ist sehr einfach. Wir müssen nur ein Objekt vom Typ JMenuBar erzeugen und dieses unserer JFrame-Instanz hinzufügen. Dies geschieht in den Zeilen 3 und 4 im oberen Quellcode.
Anschließend erzeugen wir mit den Zeilen 6 bis 12 drei JMenu-Objekte mit den Bezeichnungen File, Game und Preferences und fügen sie in die Menüleiste ein.
Mit dem Methodenaufruf in Zeile 14 rufen wir die addFileMenuItems() Methode auf und übergeben ihr als Argumente das fileMenu
-Objekt. In der aufgerufenen Methode fügen wir in das übergebene Menü-Objekt einen Menüeintrag mit dem Titel Quit ein.
Soviel zur Vorbereitung der Menüleiste. Um sie unserem Spielfenster hinzuzufügen, müssen wir die createMenu() Methode im Konstruktor aufrufen. Dies werden wir im nächsten Arbeitsschritt nachholen.
4.3 Aufrufen der Methode createMenu() im Konstruktor der GameWindow-Klasse.
Den Konstruktor der GameWindow-Klasse haben wir bereits im vorherigen Abschnitt erstellt und mit Anweisungen gefüllt. Wir fügen nun dem Konstruktor GameWindow() den Methodenaufruf createMenu() hinzu.
Dazu fügen wir die markierte Zeile in den Konstruktor unserer GameWindow-Klasse ein:
GameWindow.java
public GameWindow() { JPanel testPanel = new JPanel(); testPanel.setPreferredSize(new Dimension(600, 400)); createMenu(); add(testPanel); pack(); setTitle("PanzerHQ"); setLocation(10, 10); setResizable(false); setVisible(true); }
Mit dem Aufruf der createMenu() Methode in Zeile 6 wird die Menüleiste unseres Spielfensters erstellt und mit Menüeinträgen gefüllt.
4.4 Der komplette Quellcode der GameWindow-Klasse
Nun haben wir alle Änderungen an der GameWindow-Klasse vorgenommen. Mit dem eingefügtem Quellcode erstellen wir die Menüleister unseres Spielfensters.
In dem unten angegebenen Quellcode ist die gesamte GameWindow-Klasse zur Kontrolle für euch aufgeführt. Die neu eingefügten Zeilen sind markiert.
Der vollständiger Quelltext der Klasse GameWindow:
GameWindow.java
package de.programmierenlernenhq.panzerhq; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem; public class GameWindow extends JFrame{ public GameWindow() { JPanel testPanel = new JPanel(); testPanel.setPreferredSize(new Dimension(600, 400)); createMenu(); add(testPanel); pack(); setTitle("PanzerHQ"); setLocation(10, 10); setResizable(false); setVisible(true); } private void createMenu() { JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); JMenu gameMenu = new JMenu("Game"); JMenu prefMenu = new JMenu("Preferences"); menuBar.add(fileMenu); menuBar.add(gameMenu); menuBar.add(prefMenu); addFileMenuItems(fileMenu); } private void addFileMenuItems(JMenu fileMenu) { JMenuItem quitItem = new JMenuItem("Quit"); fileMenu.add(quitItem); } }
In NetBeans sollte die GameWindow-Klasse nun wie folgt aussehen:
In der oberen Abbildung sind die in den drei Arbeitsschritten vorgenommenen Änderungen mit einem blauen Rahmen markiert. Neben den Rahmen ist jeweils ein nummeriertes Kästchen angeordnet. Die Nummerierung entspricht der Nummerierung der oben aufgezählten Arbeitsschritte.
Als Nächstes werden wir unser Projekt ausführen und die nun integrierte Menüleiste ausprobieren.
4.5 Testen der Menüleiste unseres Spielfensters
Wir führen nun unser Java Projekt mit einem Klick auf das Run Project-Symbol aus.
Im Hintergrund wird jetzt unser Java Spiel von der NetBeans IDE erstellt und anschließend ausgeführt. Als Ergebnis wird uns das Spielfenster mit der eingefügten Menüleiste angezeigt:
In der oberen Abbildung sind die drei Menüs der erstellten Menüleiste blau unterstrichen. Bei einem Klick auf das File-Menü klappt sogar schon eine Tafel (JPopUpMenu) mit einem Eintrag (Quit) auf.
Dieser erste Menüeintrag besitzt jedoch noch keine Funktionalität. Um dies zu ändern, müssen wir für ihn noch eine Aktion hinterlegen. Dies werden wir im nächsten Abschnitt vornehmen.
5. Einen ActionListener für den Menüeintrag registrieren
Bisher reagiert unser Menü noch nicht auf Benutzereingaben. Damit ein Menüeintrag interaktiv wird, müssen wir ihm eine Aktionen zuweisen. Diese Aktion wird dann ausgeführt, sobald auf den Menüeintrag geklickt wurde.
Das ist aber noch nicht alles. Um zu wissen welche hinterlegte Aktion ausgeführt werden soll, müssen wir erkennen welcher Menüeintrag angeklickt wurde. Dazu stellt uns die Swing-Bibliothek die Listeners (Ereignisbehandler) zur Verfügung.
Je nach Art des Ereignisses stehen Schnittstellen (Interfaces) bereit, die Methoden anbieten, mit denen wir auf das eingetretene Ereignis entsprechend reagieren können. Um einen Menüklick zu erkennen und auf diesen zu reagieren, ist die ActionListener-Schnittstelle die richtige Wahl.
Die Schnittstelle können wir aber nicht direkt verwenden, sondern müssen sie vorher implementieren. Der kürzeste Weg eine Schnittstelle zu implementieren, ist das Verwenden einer anonymen inneren Klasse. Eine solche werden wir nun erstellen und damit das ActionListener-Interface implementieren.
Mehr Informationen über anonyme Klassen, könnt ihr in folgenden Beitrag finden: Anonymen Klassen in Java
Um das ActionListener-Interface zu implementieren und anschließend den ActionListener für den Quit-Menüeintrag zu registrieren, werden wir folgende Arbeitsschritte ausführen:
- Einfügen der benötigten Import-Anweisungen in die Klasse GameWindow.
- Registrieren des ActionListeners für dem Menüeintrag, durch Erweitern der Methode addFileMenuItems().
Anschließend werden wir unser Java Projekt in NetBeans ausführen und prüfen, ob der Quit-Menüeintrag nun auf Benutzereingaben mit Hilfe des ActionListeners reagiert.
5.1 Einfügen der Import-Anweisungen
Wir öffnen wieder die GameWindow-Klasse im Editor von NetBeans und fügen den folgenden Quellcode unter die bereits vorhanden Import-Anweisungen ein:
GameWindow.java
import java.awt.event.ActionEvent; import java.awt.event.ActionListener;
Als Nächstes werden wir die Methode addFileMenuItems() erweitern und in ihr den ActionListener implementieren.
5.2 Registrieren des ActionListeners für den Menüeintrag
Die Methode addFileMenuItems() haben wir bereits im vorherigen Abschnitt angelegt. Sie verfügt bisher über ein JMenuItem-Objekt mit dem Text Quit, das dem fileMenu hinzugefügt wurde. Wir wollen nun einen ActionListener für dieses Menüobjekt registrieren.
Dazu fügen wir den markierten Quellcode in die addFileMenuItems() Methode ein:
GameWindow.java
private void addFileMenuItems(JMenu fileMenu) { JMenuItem quitItem = new JMenuItem("Quit"); fileMenu.add(quitItem); quitItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); }
Auf Java Anfänger können diese sechs markierten Codezeilen ziemlich verwirrend wirken. Es ist jedoch nur halb so kompliziert wie es aussieht.
Mit der Methode addActionListener() registrieren wir ein ActionListener-Objekt für den Quit-Menüeintrag. Da es sich bei dem ActionListener jedoch um ein Interface und keine Klasse handelt, können wir ihn nicht direkt instanziieren, sondern müssen den Umweg über eine anonyme innere Klasse gehen.
In Java ist es möglich eine Klasse zu definieren und gleichzeitig dabei ein Objekt dieser Klasse zu erzeugen. Dafür benötigt diese Klasse noch nicht einmal einen Namen, daher der Begriff anonyme Klasse.
Um eine solche anonyme Klasse zu erzeugen, schreibt man das Schlüsselwort new gefolgt von einem Klassen- oder Schnittstellennamen und den Argumentenklammern. Diesem Ausdruck folgt der Klassenrumpf der zu definierenden Klasse in geschweiften Klammern.
Wenn man einen Klassennamen nach dem new-Schlüsselwort verwendet, leitet sich die anonyme Klasse von der angegebenen Klasse ab. Verwendet man hingegen einen Schnittstellennamen nach dem new-Schlüsselwort, implementiert die anonyme Klasse das angegebene Interface.
Und genau das haben wir in dem oberen Quellcode durchgeführt.
Den markierten Code kann man wie folgt verstehen: Dem quitItem-Menüeintrag soll ein Ereignisbehandlungsobjekt hinzugefügt werden. Dazu wird ein neues Objekt einer namenlosen Klasse erzeugt, welches das Interface ActionListener implementiert. Diese anonyme Klasse besitzt eine Methode actionPerformed() mit der nun definierten Implementierung und zwar soll durch sie die Java Anwendung umgehend geschlossen werden.
Die hier beschriebene Vorgehensweise für das Registrieren von Listenern werden wir noch öfter in diesem Tutorial benutzen. Mit der Zeit gewöhnt man sich an die komplexe Syntax und lernt die Vorteile von anonymen inneren Klasse zu schätzen.
Als Nächstes werden wir unser Projekt ausführen und den nun interaktiven Menüeintrag Quit testen.
5.3 Testen des Quit Menüeintrags unseres Spielfensters
Wir führen nun unser Java Projekt mit einem Klick auf das Run Project-Symbol aus.
Im Hintergrund wird jetzt unser Java Spiel von der NetBeans IDE erstellt und anschließend ausgeführt. Als Ergebnis wird uns das bekannte Spielfenster angezeigt. Diesmal schließt sich unsere Java Anwendung, wenn wir auf dem Menüeintrag Quit des File-Menüs klicken.
In der oberen Abbildung ist der Quit-Menüeintrag des File-Menüs blau unterstrichen. Mit einem Klick auf Quit kann unsere Java Anwendung von nun an beendet werden.
Jetzt haben wir das Rahmenwerk unseres Spielfensters fast komplett erstellt. Es fehlt nur noch ein WindowListener mit dem wir auf Fensterereignisse reagieren können. Einen solchen werden wir im nächsten Abschnitt für unser GameWindow-Objekt registrieren.
6. Einen WindowListener für unser Spielfenster registrieren
Auch bei Programmfenstern können Ereignisse eintreten. Mit einem WindowListener ist es möglich auf die verschiedenen Fensterereignisse zu reagieren, bspw. wenn das Fenster geschlossen wird.
Dazu müssen wir das WindowListener-Interface implementieren und für das Fenster registrieren, das von dem Listener überwacht werden soll. In unserem Fall also das Spielfenster.
Dies werden nun mit den folgenden Arbeitsschritten umsetzen:
- Einfügen der benötigten Import-Anweisungen in die Klasse GameWindow.
- Erstellen der Methode registerWindowListener() mit der wir den WindowListener implementieren und für unser Spielfenster registrieren.
- Aufrufen der Methode registerWindowListener() im Konstruktor der Klasse GameWindow.
Anschließend werden wir unser Java Projekt in NetBeans ausführen und prüfen, ob der sich unser Java Spiel mit einem Klick auf das Fenster schließen-Symbol beenden lässt.
6.1 Einfügen der Import-Anweisungen
Wir öffnen wieder die GameWindow-Klasse im Editor von NetBeans und fügen den folgenden Quellcode unter die bereits vorhanden Import-Anweisungen ein:
GameWindow.java
import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent;
Als Nächstes werden wir die Methode registerWindowListener() erstellen und in ihr den WindowListener implementieren.
6.2 Erstellen der Methode registerWindowListener()
Wir werden nun die Methode registerWindowListener() in unserer GameWindow-Klasse definieren. Dazu fügen wir die folgende Methodendefinitionen direkt nach dem Konstruktor der GameWindow-Klasse ein:
GameWindow.java
private void registerWindowListener() { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } @Override public void windowDeactivated(WindowEvent e) { // hier werden wir später unser Spiel pausieren } @Override public void windowActivated(WindowEvent e) { // hier werden wir später unser Spiel wieder fortsetzen } }); }
Diesmal haben wir das Listener-Interface auf eine andere Art implementiert. Wir haben zwar wieder eine anonyme innere Klasse erzeugt, diese aber diesmal nicht direkt vom Interface WindowListener abgeleitet, sondern von der Klasse WindowAdapter.
Ein WindowAdapter ist eine abstrakte Klasse, die Fensterereignisse empfängt. Sie implementiert alle Interface-Methoden der Schnittstellen WindowListener, WindowStateListener und WindowFocusListener, jedoch mit leeren Methodenrumpf. Wir müssen daher nur die Interface-Methoden ausprogrammieren, die für uns von Bedeutung sind. Alle anderen bleiben leere Methoden.
Weitere Infos über die WindowAdapter-Klasse könnt ihr hier finden: http://docs.oracle.com/javase/7/docs/api/java/awt/event/WindowAdapter.html
Als Methoden des WindowListener-Interfaces haben wir die Methoden windowClosing(), windowDeactivated() und windowActivated() überschrieben. Von den drei Methoden haben wir nur die erste mit einer Anweisung gefüllt.
Durch sie lassen wir unsere Java Anwendung beenden, indem wir die statische Methode exit() der Klasse System aufrufen. Den Rumpf der anderen beiden Methoden werden wir später mit Quellcode füllen und durch sie unser Java Spiel pausieren bzw. wieder fortsetzen lassen.
Um den jetzt implementierten WindowListener für unser Spielfenster zu registrieren, müssen wir die registerWindowListener() Methode im Konstruktor aufrufen. Dies werden wir im nächsten Arbeitsschritt vornehmen.
6.3 Aufrufen der Methode registerWindowListener() im Konstruktor der GameWindow-Klasse.
Den Konstruktor der GameWindow-Klasse haben wir bereits erstellt und mit Anweisungen gefüllt. Wir fügen nun dem Konstruktor GameWindow() den Methodenaufruf registerWindowListener() hinzu.
Dazu fügen wir die markierte Zeile in den Konstruktor unserer GameWindow-Klasse ein:
GameWindow.java
public GameWindow() { JPanel testPanel = new JPanel(); testPanel.setPreferredSize(new Dimension(600, 400)); registerWindowListener(); createMenu(); add(testPanel); pack(); setTitle("PanzerHQ"); setLocation(10, 10); setResizable(false); setVisible(true); }
Mit dem Aufruf der registerWindowListener() Methode in Zeile 6 wird der WindowListener für unser Spielfensters registriert und dabei auch mit Hilfe einer anonymen inneren Klasse implementiert.
6.4 Der komplette Quellcode der GameWindow-Klasse
Nun haben wir alle Änderungen an der GameWindow-Klasse vorgenommen. Mit dem eingefügtem Quellcode implementieren und registrieren wir einen WindowListener für unsere Spielfensters.
In dem unten angegebenen Quellcode ist die gesamte GameWindow-Klasse zur Kontrolle für euch aufgeführt. Die in diesem und dem vorherigen Abschnitt eingefügten Zeilen sind markiert.
Der vollständiger Quelltext der Klasse GameWindow:
GameWindow.java
package de.programmierenlernenhq.panzerhq; import java.awt.Dimension; import javax.swing.JFrame; import javax.swing.JPanel; import javax.swing.JMenuBar; import javax.swing.JMenu; import javax.swing.JMenuItem; import java.awt.event.ActionEvent; import java.awt.event.ActionListener; import java.awt.event.WindowAdapter; import java.awt.event.WindowEvent; public class GameWindow extends JFrame{ public GameWindow() { JPanel testPanel = new JPanel(); testPanel.setPreferredSize(new Dimension(600, 400)); registerWindowListener(); createMenu(); add(testPanel); pack(); setTitle("PanzerHQ"); setLocation(10, 10); setResizable(false); setVisible(true); } private void registerWindowListener() { addWindowListener(new WindowAdapter() { @Override public void windowClosing(WindowEvent e) { System.exit(0); } @Override public void windowDeactivated(WindowEvent e) { // hier werden wir später unser Spiel pausieren } @Override public void windowActivated(WindowEvent e) { // hier werden wir später unser Spiel wieder fortsetzen } }); } private void createMenu() { JMenuBar menuBar = new JMenuBar(); this.setJMenuBar(menuBar); JMenu fileMenu = new JMenu("File"); JMenu gameMenu = new JMenu("Game"); JMenu prefMenu = new JMenu("Preferences"); menuBar.add(fileMenu); menuBar.add(gameMenu); menuBar.add(prefMenu); addFileMenuItems(fileMenu); } private void addFileMenuItems(JMenu fileMenu) { JMenuItem quitItem = new JMenuItem("Quit"); fileMenu.add(quitItem); quitItem.addActionListener(new ActionListener() { @Override public void actionPerformed(ActionEvent e) { System.exit(0); } }); } }
In NetBeans sollte die GameWindow-Klasse nun wie folgt aussehen:
In der oberen Abbildung sind die in den drei Arbeitsschritten vorgenommenen Änderungen mit einem blauen Rahmen markiert. Neben den Rahmen ist jeweils ein nummeriertes Kästchen angeordnet. Die Nummerierung entspricht der Nummerierung der oben aufgezählten Arbeitsschritte. Die Änderungen aus dem vorherigen Abschnitt sind mit Orange markiert.
Als Nächstes werden wir unser Java Projekt ausführen und den WindowListener erproben.
6.5 Testen des WindowListeners unseres Spielfensters
Wir führen nun unser Java Projekt mit einem Klick auf das Run Project-Symbol aus.
Im Hintergrund wird jetzt unser Java Spiel von der NetBeans IDE erstellt und anschließend ausgeführt. Als Ergebnis wird uns das bekannte Spielfenster angezeigt. Diesmal sollte sich unsere Java Anwendung auch mit einem Klick auf das Fenster schließen-Symbol beenden lassen.
In der oberen Abbildung ist unser Spielfenster zu sehen. Unsere Java Anwendung lässt sich nun auch beenden, wenn auf das Fenster schließen-Symbol geklickt wird.
Jetzt haben wir das komplette Rahmenwerk unseres Spielfensters erstellt. In den nächsten Lektionen werden wir zwar noch einige Zeilen Quellcode in die GameWindow-Klasse einfügen, aber nur um unser Spielfenster zu erweitern. Am Rahmenwerk wird sich nichts mehr ändern.
Zusammenfassung
In der zweiten Lektion unseres Java Spiel Programmieren Tutorials haben wir das Spielfenster erstellt. Dabei haben wir einige grafische Elemente der Swing-Bibliothek von Java kennengelernt.
Das Spielfenster wird durch eine eigene Klasse, die GameWindow-Klasse, repräsentiert. Diese haben wir zu Beginn dieser Tutorial Lektion mit der NetBeans IDE erstellt. Anschließend haben wir dem JFrame, also dem Fensterrahmen unseres Spielfensters, eine eigene Zeichenfläche (JPanel) zugefügt. Auf dieser Zeichenfläche werden wir später unsere Spielobjekte darstellen.
Danach haben wir das Spielfenster um ein Menü erweitert. Dazu haben wir ein JMenuBar-Objekt erzeugt und es mit Menüeinträgen gefüllt. Damit das Menü auch auf Benutzereingaben reagiert, haben wir ihm einen ActionListener hinzugefügt.
Am Ende dieser Lektion haben wir für das Spielfenster zudem einen WindowListener registriert. Mit dem WindowListener reagieren wir auf Fensterereignisse, z.B. wenn das Spielfenster geschlossen wird. Beide Listenern haben wir mit Hilfe von anonymen inneren Klassen implementiert.
In der nächsten Lektion unseres Java Spiele Programmieren Tutorials werden wir die Spielfläche erstellen und in der Spielfenster anzeigen lassen.
Comments 15
Kann man diese Klassen auch mit ,,Brackets“ machen, weil ich wüsste nicht wie könntest du mir bitte helfen ich möchte so schnell wie möglich weiter das Spiel programmieren!!!
Weiter so die tutorials sind so nice!!!
🙂
Hey, wirklich tolles Tutorial. Danke dafür!
Eine Frage habe ich allerdings:
Wozu zweimal der system.exit(0) Befehl? Wir haben diesen ja einmal als ActionListener auf der „Quit-Taste“ des Filemenüs implementiert (ab da lässt sich die Anwendung mit einem Klick auf „Quit“ auch bereits schließen) und dann noch einmal im Windowlistener unter der Bedingung, dass das Fenster geschlossen wird.
Besten Dank im Voraus für die Antwort!
Author
Hallo Ve,
danke für dein Lob!
Dies haben wir nur zum Verbessern der Benutzererfahrung gemacht. Einige Benutzer sind es gewohnt, Anwendungen über das X am rechten oberen Fensterrand zu schließen. Andere Nutzer verwenden stattdessen lieber einen Menüeintrag.
Viele Grüße,
Chris
Hmmm sorry, ich habe das unnötig umständlich formuliert…
Was ich meinte ist, wenn man an dieser Stelle des Tutorials den Befehl
registerWindowListener();
im GameWindow-Konstruktor auskommentiert oder weglässt, funktioniert das Fenster augenscheinlich genauso wie wenn man ihn hinschreibt.
Man könnte also -so sieht es jetzt gerade für mich aus- die ganze Funktion
@Override
public void windowClosing(WindowEvent e) {
System.exit(0);
}
aus der registerWindowListener()-Funktion entfernen um Code zu sparen, falls du jetzt nicht sagst, dass das für etwas bestimmtes sehr wichtig ist, was ich gerade übersehe.
Author
Hallo Ve,
OK, danke für den Hinweis. Ich habe das bisher so noch nicht ausprobiert. Wenn ich Zeit finde werde ich mir das mal ganz genau anschauen. Ich bin sehr gespannt darauf zu sehen, warum sich das Fenster auch ohne den Listener schließen lässt. Dies sollte mit Hilfe des Debuggers nachvollzogen werden können.
Viele Grüße,
Chris
Hallo Ve,
es ist so, dass wenn du das Fenster mit dem „X“ schließt, ohne die System.exit(0) Anweisung, wird das Fenster ja geschlossen, das Programm hingegen, wird aber nicht beendet. Dies kannst du dir in der Konsole mal genauer anschauen, wird das Programm beendet, erhälst du eine Ausgabe in der Konsle. Eine Alternative zum Schließen des Programms wäre die setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); Anweisung.
Zusammenfassend gesagt, müssen beim Schließen des Fensters darauf achten, dass auch das Programm beendet wird, damit das Programm nicht im Hintergrund weiter läuft xD
Super Tutorial Dankeschön!
funktioniert
Beste Tuto Dankeschön !!
Hallo,
hätte da ein Problem und bekomme das als Anfänger nicht alleine gelöst:
In Kapitel „3. Das Spielfenster erstellen und anzeigen lassen“ füge ich euren Quellcode ein allerdings bringt mir Netbeans die Warnmeldung „Overridable method call in constructor“.
Die Meldung erscheint jeweils in den Zeilen:
add(testPanel);
pack();
setTitle(„PanzerHQ“);
setLocation(10, 10);
setResizable(false);
setVisible(true);
Ich denke deshalb erscheint mein „Game Window“ nicht wenn ich das Projekt durchlaufen lasse (Aufgabe in einem der folgenden Kapitel). Bekomme sonst allerdings keine Fehlermeldung und in der Console steht unter „run:“ der Text „BUILD SUCCSESSFUL“.
Was kann ich tun? Bitte um Hilfe.
Viele Grüße
Author
Hallo Kakashi,
ohne Quellcode ist es sehr schwierig die Fehlerursache zu finden. Wenn du möchtest, kannst Du mir deine Projektdateien als ZIP per E-Mail zusenden. Die E-Mail Adresse kannst Du im Impressum finden. Ich schaue dann mal, ob ich etwas herausfinden kann.
Viele Grüße, Chris
also ich versuche das Game Windo zu erstellen habe auch eins zu eins euren Code bei mir in Netbeams stehen und der spuckt mir eine fehlermeldung aus zb bei der 14 Zeile add(testPanel) sagt er mir irgendwas mit variabel, dass die glaube nicht da sei und auf der anderen seite klappt ne GameWindow nicht, ich könnte echt durchdrehen ich habs genau wie ihr gemacht werde hier aber nicht schlau von…
Author
Hallo Slimejoker,
vielleicht ist es ein Tippfehler. Wenn du möchtest, kannst du uns deine Projektdateien (oder nur die Quellcode-Dateien) per Mail zuschicken. Die E-Mail Adresse findest du im Impressum. Wir werden dann mal auf Fehlersuche gehen.
Viele Grüße, Chris
Hallo,
wieso kann ich nicht den Link für das Tutorial „Vor: Ein Spielobjekt in Java erstellen“ öffnen?
Danke für Eure Antworten.
Viele Grüße
Rolo78
Author
Hallo Rolo78,
der Link ist noch nicht aktiv, da der dritte Teil des Java Spiel Programmieren Tutorial noch nicht veröffentlicht worden ist. Sobald Teil 3 fertig erstellt wurde, werde ich ihn veröffentlichen. Dann wird auch der Link aktiviert werden. Es wird aber noch etwas dauern, bis wir so weit sind.
Viele Grüße, Chris
Pingback: Java Spiel Programmieren Tutorial - Das Java Projekt anlegen