Swing ist eine Bibliothek zur Erstellung graphischer Benutzungsoberflächen und ein Teil der Java Foundation Classes, die 1997 bei der JavaOne Developer Conference vorgestellt wurden. Swing löst damit das AWT-Toolkit von JDK 1.1 ab.
Das offizielle Tutorial zu Swing befindet sich auf den Sun-Seiten. Die ersten beiden Kapitel geben eine Einführung, die für kleinere Aufgaben vollständig ausreichend ist. Die Informationen zu den Layout-Managern sind ebenfalls sehr hilfreich.
Ebenfalls hilfreich kann der Teil über Graphische Benutzungsoberflächen der Vorlesung "Grundlagen der Informatik I" von Frau Prof. Mezini und Herrn Prof. Ostermann sein. Dieses Tutorial basiert auf den ebenfalls in dieser Veranstaltung verwendeten Sourcen zu TicTacToe. Wir implementieren im Folgenden die Klasse TicTacToeView.java Schritt für Schritt nach. Die kompletten Sourcen sind im Archiv tictactoe_source.zip zu finden.
public class TicTacToeView extends JFrame implements Observer
{
private TicTacToeModel model;
private TicTacToeController controller;
private JButton[][] mBtns; // button array
public void won(Player i) {...}
public void tie() {...}
public void changed(int row, int col) {...}
public void reset() {...}
public TicTacToeView(TicTacToeModel model, TicTacToeController controller) {
this.model = model; this.controller = controller;
viewInit(); callbackInit(); setSize(300, 300); setTitle("TicTacToe");
model.addObserver(this);
} }
private void viewInit() { int iRow; // button row int iCol; // button column Container pane; // content pane
// get content pane, set to grid layout pane = getContentPane(); pane.setLayout(new GridLayout(3, 3)); // create and attach buttons mBtns = new JButton[3][3]; for (iRow = 0; iRow < 3; iRow++) { for (iCol = 0; iCol < 3; iCol++) { mBtns[iRow][iCol] = new JButton(); pane.add(mBtns[iRow][iCol]); } } }
Als nächstes wird ein Spielfeld erzeugt. Dazu greifen wir das erste Mal auf den sogenannten ContentPane Container zu. Er enthält alle sichtbaren Elemente und ist daher genau der richtige Ort um einige Buttons hinzuzufügen. Zunächst wird das Layout der Buttons mit einem sogenannten LayoutManager festgelegt. Da wir unsere Buttons rasterförmig anordnen möchten, verwenden wir ein GridLayout. Das Layout des ContentPanes wird also auf GridLayout gesetzt und anschließend neun Buttons hinzugefügt
private void callbackInit() { int iR; // row and column loop indices int iC; for (iR=0; iR<3; iR++) { for (iC = 0; iC < 3; iC++) { final int row = iR; final int col = iC; mBtns[iR][iC].addActionListener(new ActionListener() { public void actionPerformed(ActionEvent e) { controller.playerMove(row,col); } }); } } }Im markierten Teil wird ein sogenannter ActionListener erzeugt und bei allen Buttons als Observer angemeldet. Observer stellt unter anderem aus diesem Grund ein sehr häufig gebrauchtes Entwurfsmuster in der GUI-Programmierung dar.
public interface Observer {Wir erinnern uns, dass wir den View zu Beginn als Observer beim Model angemeldet haben. Allerdings nicht direkt, sondern über das obige Interface. Diese Methoden werden nun vom Model ausgeführt um die View zu verändern. Wir implementieren nun die Methoden des Interfaces die bisher noch leer sind:
public void changed(int row, int col); public void won(Player player); public void tie(); public void reset(); }
public void won(Player i) {
JOptionPane.showMessageDialog(this,"Player "+i.ordinal()+" won!" ,
"Game Over", JOptionPane.INFORMATION_MESSAGE);
}
public void tie() {
JOptionPane.showMessageDialog(this, "Tie - Nobody wins",
"Game Over", JOptionPane.INFORMATION_MESSAGE);
}
public void changed(int row, int col) {
mBtns[row][col].setText(model.getOwnerOfFigureOnPlayingField(row,col).name());
}
public void reset() {
int iR, iC;
for (iR=0; iR<3; iR++)
for (iC = 0; iC < 3; iC++)
mBtns[iR][iC].setText("");
}
Wenn das Programm jetzt gestartet wird, steht einer kleinen Partie TicTacToe nichts mehr im Wege!