Zur praktischen Anwendung der vermittelten Kenntnisse wird in diesem Teil des Kapitels erläutert, wie die grafische Bedienungsoberfläche auf Swing umgestellt werden kann, die bereits in Kapitel 4.6 mittels AWT-Komponenten implementiert wurde. Auf die Erklärung der Klassenhierarchie dieses Beispiels wird dabei verzichtet, da diese mit der in Kapitel 4.6 beschriebenen Klassenhierarchie übereinstimmt. Es sei nochmals darauf hingewiesen, dass insbesondere die Verwendung von Swing-Komponenten der Hauptbestandteil aller folgenden Klassenerläuterungen ist. Die Aufgabe des Hauptprogramms und der in diesem Kapitel betrachteten Klassen gleicht daher den in Kapitel 4.6 beschriebenen Konzepten. Zum einfachen Verständnis der Zusammenhänge wurden in diesem Anwendungsbeispiel die Namen der Klassen mit einem vorangestellten „J" versehen. Somit entspricht die Klasse JGUISVUser der in Kapitel 4.6 verwendeten AWT-Klasse GUISVUser. Folglich kann an dieser Stelle auf die Erklärung der Logik des Programmablaufs verzichtet und die Darstellung auf die Benutzung der Swing-Komponenten konzentriert werden. Hauptprogramm Aufgabe des Applets, das in der Klasse JGUISVUser implementiert ist, ist die Steuerung der gesamten Client-Anwendung. Diese Implementierung soll nun Schritt für Schritt durchgegangen werden. Setzt man die Code-Stücke wieder zusammen, so erhält man das übersetzungsfähige Applet. import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; public class JGUISVUser extends JApplet { JSpielCanvasPos1 sc1; JSpielCanvas sc2; JSpielfeld spieler, computer; JButton shoot; JButton setship; JPanel computerPanel; JPanel spielerPanel; JPanel buttonsPanel; Container thisApplet; // Alle weiteren Methoden und innere Klassen dieses Applets } Zunächst werden die Komponenten der Packages java.awt, java.awt.event, javax.swing und javax.swing.border importiert. Das Importieren des Packages java.awt ist notwendig, um auf die Klasse Container zugreifen zu können. Da die Klasse JApplet, wie in Kapitel 8.3 erläutert wurde, zu den Top-Level-Komponenten zählt, stellt JApplet kein JComponent-Objekt, sondern ein Container-Objekt dar. JGUISVUser ist ein JApplet-Objekt und wird durch die init-Methode initialisiert. public void init () { thisApplet = this; getContentPane().setLayout(new GridLayout(1,3)); setSize(700,266); Wie im vorangegangenen Code-Segment dargestellt ist, kann der Layout-Manager nicht direkt auf das JApplet-Objekt angewendet werden, sondern nur auf dessen Inhalt, der durch die Methode getContentPane() zurückgeliefert werden kann. Würde hier ein BoxLayout anstelle des GridLayout-Objekts verwendet, so wäre die Benutzung der folgenden Zeile notwendig: getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); Im Folgenden werden die weiteren Komponenten dieses Applets initialisiert. Die Spielbereiche JSpielCanvas und JSpielCanvasPos1 werden nicht direkt in das Applet eingebettet. Anstelle dessen werden Hilfs-Panels benutzt, damit der Ansatz des Packages javax.swing.border verdeutlicht werden kann. computer = new JSpielfeld(); spieler = new JSpielfeld(); buttonsPanel = new JPanel(false); buttonsPanel.setLayout(new FlowLayout(FlowLayout.CENTER)); computerPanel = new JPanel(false); computerPanel.setLayout(new BoxLayout(computerPanel, BoxLayout.Y_AXIS)); computerPanel.setBorder( new TitledBorder(new TitledBorder(LineBorder.createGrayLineBorder(),"Spielfeld des"), "Computers", TitledBorder.RIGHT, TitledBorder.BOTTOM)); spielerPanel = new JPanel(false); spielerPanel.setLayout(new BoxLayout(spielerPanel, BoxLayout.Y_AXIS)); spielerPanel.setBorder( new TitledBorder(new TitledBorder(LineBorder.createGrayLineBorder(),"Spielfeld des"), "Spielers", TitledBorder.RIGHT, TitledBorder.BOTTOM)); Sowohl das Objekt computerPanel als auch das Objekt spielerPanel werden mit dem Objekt TitledBorder eingerahmt. Auf der oberen linken Seiten wird der String „Spielfeld des" ausgegeben, auf dem unteren rechten Rand das Wort „Spieler" bzw. „Computer". Im Anschluss daran werden die benötigten Buttons initialisiert. setship = new JButton("Neues Spiel"); setship.setToolTipText("Neues Spiel"); setship.addActionListener(new ButtonListener(0)); buttonsPanel.add(setship); shoot = new JButton("Schuss abgeben"); shoot.setToolTipText("Klick mich, um zu schiessen"); shoot.setEnabled(false); shoot.addActionListener(new ButtonListener(1)); buttonsPanel.add(shoot); getContentPane().add(buttonsPanel); Die Buttons werden direkt dem Objekt buttonsPanel hinzugefügt, das anschließend in das Objekt ContentPane des JApplets integriert wird. Jedem Button wird ein ActionListener-Objekt hinzugefügt. Auf die Verwendung der Klasse ButtonListener wird hier nicht weiter eingegangen, da sie identisch zu der in Kapitel 4.6 beschriebenen Funktionsweise ist. Das restliche Programm, also insbesondere die Event-Verarbeitung, ist vollständig mit der in Kapitel 4.6 beschriebenen Funktionsweise identisch. Die Bedienungsoberfläche dieses Applets ist in Abb. 8-31 dargestellt. Abb. 8.31: Bedienungsoberfläche des JGUISVUser-Applets Klasse JSchiffFenster In der Klasse JSchiffFenster werden die Objekte für die Zuordnung der Schiffe und des gesamten Spielfelds deklariert. import java.awt.*; import java.awt.event.*; import javax.swing.*; import javax.swing.border.*; import javax.swing.event.*; public class JSchiffFenster extends JFrame implements ActionListener{ JSpielCanvas sc1; JSpielfeld s; JQuadrate q[]; // beinhaltet plazierPanel und schiffePanel und der Fertig-Button JPanel topPanel; // Das gGesamt-Panel worauf ein Schiff mit seiner Bezeichnung // stehen soll. JPanel schiffePanel; JLabel label3; // Bezeichnung für einen Schiff // für die unteren Labels: l1 und l2 JPanel bottomPanel; JLabel l1; JLabel l2; Im Konstruktor wird sowohl das Spielfeld-Objekt als auch der hierzu gehörige Vater-Container initialisiert (das JApplet-Objekt). public JSchiffFenster(JSpielfeld s, Container c) { this.parentApplet = c; this.s = s; thisFrame = this; s.initialisieren(); q = new JQuadrate[5]; // Teile den Frame in horizontaler Richtung getContentPane().setLayout(new BoxLayout(getContentPane(), BoxLayout.Y_AXIS)); setSize(300,250); Das Fenster JSchiffFenster verwendet vertikal das BoxLayout (Y_AXIS), damit die zwei Panels topPanel und bottomPanel eingefügt werden können. topPanel = new JPanel(false); topPanel.setLayout(new BoxLayout(topPanel, BoxLayout.X_AXIS)); topPanel.setBorder(BorderFactory.createTitledBorder(BorderFactory.cr eateEmptyBorder(10,10,10,10), "")); Das Layout des Objekts topPanel wird hierbei auf BoxLayout gesetzt. Allerdings wird es hier horizontal (X_AXIS) aufgeteilt, damit die einzufügenden Panels nebeneinander erscheinen können. Dieses Panel erhält keinen Titel und wird von einem leeren Rand der Dicke 10 Pixel umrandet. Im Anschluss daran wird das Objekt PlazierPanel definiert, mit einem Titel versehen und eine Instanz des Objekts JSpielCanvasPos2 hinzugefügt. //Spielfeld des Benutzers plazierPanel = new JPanel(false); plazierPanel.setLayout(new BoxLayout(plazierPanel, BoxLayout.Y_AXIS)); plazierPanel.setBorder( new TitledBorder(new TitledBorder(LineBorder.createGrayLineBorder(),"Bitte Plaziere die"), "Schiffe", TitledBorder.RIGHT, TitledBorder.BOTTOM)); topPanel.add(plazierPanel); sc1 = new JSpielCanvasPos2(s, q); plazierPanel.add(sc1); Anschließend wird dem Objekt topPanel ein weiteres Panel hinzugefügt, das anzeigt, welche Schiffe noch gesetzt werden müssen. Die Information über die frei verfügbaren Schiffe werden anhand der Methode ZeigeQuadrate(), die im Folgenden näher erklärt wird, dargestellt. //Infofelder schiffePanel = new JPanel(false); schiffePanel.setLayout(new BoxLayout(schiffePanel, BoxLayout.Y_AXIS)); schiffePanel.setBorder( new TitledBorder(new TitledBorder(LineBorder.createGrayLineBorder(),"Vorhandene"), "Schiffe", TitledBorder.RIGHT, TitledBorder.BOTTOM)); topPanel.add(schiffePanel); zeigeQuadrat("2-er Schiff", 0); zeigeQuadrat("3-er Schiff 1",1); zeigeQuadrat("3-er Schiff 2", 2); zeigeQuadrat("4-er Schiff", 3); zeigeQuadrat("5-er Schiff", 4); Ein Button, der durch eine Betätigung das Fenster schließt, sobald alle Schiffe platziert sind, wird durch das folgende Code-Segment definiert. // Anlegen eines Buttons JButton fertig = new JButton("Fertig"); fertig.setToolTipText("Klicke erst, wenn alle Schiffe positioniert sind."); fertig.addActionListener(this); topPanel.add(fertig); Anschließend werden zwei Informations-Labels definiert und dem Objekt bottomPanel hinzugefügt. bottomPanel = new JPanel(false); bottomPanel.setLayout(new GridLayout(2,0)); JLabel l1 = new JLabel("Zum Setzen der Schiffe bitte Anfangs- und Endposition mit der Maus markieren", JLabel.LEFT); bottomPanel.add(l1); JLabel l2 = new JLabel("Zum Entfernen der Schiffe bitte Anfangs- und Endposition nochmals mit der Maus markieren",JLabel.LEFT); bottomPanel.add(l2); Zum Schluss werden die zwei Haupt-Panels in den Inhaltsbereich des Objekts JApplets eingefügt. getContentPane().add(topPanel); getContentPane().add(bottomPanel); Methode zeigeQuadrat Aufgabe der Methode zeigeQuadrat ist es, das Objekt hilfPanel zu erstellen, das sowohl ein Quadrat-Objekt als auch eine Beschriftung dieses Objektes enthält. Dieses Panel wird anschließend dem Objekt schiffePanel hinzugefügt. protected void zeigeQuadrat(String name, int schiffNummer) { // hilfPanle stellt einen Shiff mit dessen Label dar JPanel hilfPanel = new JPanel(false); hilfPanel.setLayout(null); q[schiffNummer] = new JQuadrate(s, schiffNummer); q[schiffNummer].setBounds(5,5,16,16); hilfPanel.add(q[schiffNummer]); label3 = new JLabel(name); label3.setBounds(30,5,100,20); hilfPanel.add(label3); schiffePanel.add(hilfPanel); validate(); } Methode actionPerformed Die Methode actionPerformed wurde bereits in Kapitel 4.6 erklärt. Den einzigen Unterschied zu der hier verwendeten Methode stellt der Aufruf des Objekts JOptionPane (Dialogfenster) dar. Der Vorteil dieses Vorgehens liegt in der Tatsache begründet, dass diese Klasse automatisch ein Informations-Icon erstellt und nur eine Zeile zur Anzeige benötigt. Die Bedienungsoberfläche des Fensters ist in Abb. 8-32 dargestellt. Abb. 8.32: Bedienungsoberfläche der Klasse SchiffFenster //Fehlermeldung JOptionPane.showMessageDialog(thisFrame, "Erst alle Schiffe setzen!!"); Klasse JQuadrat Die Klasse JQuadrat entspricht in ihrem Aufbau und in ihrer Funktion der Klasse Quadrat, die in Kapitel 4.6 erklärt wurde. Der einzige Unterschied besteht in der Importierung der Swing-Komponenten und damit in der Definition dieser Klasse, die die Klasse JPanel anstelle der Klasse Panel, die in Kapitel 4.6 verwendet wurde, erweitert: import javax.swing.*; class JQuadrate extends JPanel { // Der Rumpf dieser Klasse entspricht der Klasse Quadrat } Weitere Klassen Die Erweiterungen bzw. die Veränderungen der bisher nicht dargestellten Klassen, die für dieses Beispiel entwickelt worden sind, unterscheiden sich von den in Kapitel 4.6 dargestellten AWT-Klassen in derart geringem Maße, dass auf ihre ausführliche Erläuterung verzichtet werden kann. Im Folgenden werden daher lediglich die wichtigsten Unterschiede aufgelistet: Klasse JSelectionAreaPos2 In dieser Klasse wird anstelle der selbst definierten Klasse DialogFehler die Klasse JOptionPane verwendet. Klasse JSpielCanvas Diese Klasse erweitert die Klasse javax.swing.JPanel anstelle der Klasse java.awt.Panel. Alle weiteren Klassen können in identischer Form übernommen werden.