Grundlagen der Programmierung 2 SS 2005 - Datei Memory.java
import java.awt.*; import java.awt.event.*; import javax.swing.*; public class Memory extends JFrame { private JLabel timeLabel; private TimeCounter time; // Konstruktor public Memory() { super("Memory"); // Unser Zeitmesser time = new TimeCounter(this); // Nur ein Listener-Objekt fuer alle Felder: MemoryListener memListener = new MemoryListener(time); Container content = this.getContentPane(); content.setLayout(new BorderLayout()); JPanel buttonPanel = new JPanel(); buttonPanel.setLayout(new GridLayout(4, 4)); // Buttons fuer die Felder erzeugen: for (int i = 0; i < 16; i++) { CharButton b = new CharButton(this.getCharacter()); buttonPanel.add(b); b.addActionListener(memListener); b.cover(); } // Label fuer die Zeitanzeige timeLabel = new JLabel("00:00", JLabel.CENTER); timeLabel.setFont(new Font(null, Font.PLAIN, 20)); // Elemente auf den ContentPane packen content.add(buttonPanel, BorderLayout.CENTER); content.add(timeLabel, BorderLayout.SOUTH); setSize(300, 350); setDefaultCloseOperation(EXIT_ON_CLOSE); setVisible(true); // Zeitmessung starten time.start(); } // Die Beschriftungen der Felder: private String[] labels = { "A", "B", "C", "D", "E", "F", "G", "H", "A", "B", "C", "D", "E", "F", "G", "H" }; private int labelsLength = labels.length; private String getCharacter() { // Waehlt einen Label zufaellig aus dem Array // und entfernt ihn daraus. int pos = (int) (Math.random() * 100) % labelsLength; String c = labels[pos]; // Luecke im Array schliessen: for (int i = pos + 1; i < labelsLength; i++) { labels[i - 1] = labels[i]; } labelsLength--; return c; } public void drawCurrentTimeString(String timeString) { timeLabel.setText(timeString); } public static void main(String[] args) throws Exception { Memory m = new Memory(); } } // separate Klasse fuer den Listener: class MemoryListener implements ActionListener { // Die bisher aufgedeckten Felder: private CharButton firstSelection = null; private CharButton secondSelection = null; // Zaehler fuer die bisher entdeckten Paare private int pairsFound = 0; // Referenz auf den Zeitmesser private TimeCounter time; // Konstruktor public MemoryListener(TimeCounter time) { super(); this.time = time; } public void actionPerformed(ActionEvent e) { // Das gerade gewaehlte Feld: CharButton flipped = (CharButton) e.getSource(); // Drei Zustaende: // kein, ein, zwei Feld(er) ist/sind aufgedeckt: if (firstSelection == null) { // kein Feld - nun das erste: firstSelection = flipped; flipped.setEnabled(false); flipped.uncover(); } else if (secondSelection == null) { // ein Feld - nun das zweite: flipped.setEnabled(false); flipped.uncover(); secondSelection = flipped; if (firstSelection.getChar().equals(secondSelection.getChar())) { // Die Marken sind gleich: firstSelection.setBackground(Color.BLACK); secondSelection.setBackground(Color.BLACK); // Neue Wahl vorbereiten: firstSelection = null; secondSelection = null; // Zaheler erhoehen pairsFound++; // Spiel beendet? if (pairsFound == 8) { // Zeitmesser stoppen time.stopIt(); JOptionPane.showMessageDialog(null, "You have completetd the game in " + time.getTimeString() + "!", "Memory", JOptionPane.INFORMATION_MESSAGE); } } else { // Die Marken sind verschieden // Sie bleiben aufgedeckt bis zur naechsten Wahl } } else { // Nach einem Fehlversuch wurde drittes Feld aufgedeckt: flipped.setEnabled(false); flipped.uncover(); firstSelection.cover(); firstSelection.setEnabled(true); firstSelection = flipped; secondSelection.cover(); secondSelection.setEnabled(true); secondSelection = null; } } } // Hilfsklasse: Button-Unterklasse mit verdeckbarer Beschriftung: class CharButton extends JButton { private String myLabel; CharButton(String lab) { super(lab); myLabel = lab; } void uncover() { setText(myLabel); } void cover() { setText(""); } String getChar() { return myLabel; } } // Klasse zum Messen der Zeit class TimeCounter extends Thread { // wie spät war es als das Spiel gestartet wurde? private long startTime; // Referenz auf den Memory-Frame private Memory mem; // Kontrollvariable für den Thread private boolean running; // Konstruktor mit Uebergabe des Memory-Frames public TimeCounter(Memory owner) { mem = owner; } // liefert die seit Spielbeginn vergangene Zeit in Sekunden private int getDuration() { long deltaTime = System.currentTimeMillis() - startTime; // vergangene Zeit in Millisekunden in Sekunden umrechnen // dabei wird abgerundet return (int) (deltaTime / 1000L); } // Wandelt die aktuelle Zeit in einen passenden String um public String getTimeString() { int time = getDuration(); // Bestimmung von Minuten und Sekunden int minutes = time / 60; int seconds = time % 60; String timeString; // Fuehrende Nullen erkennen und String zusammenfuegen if (minutes < 10) timeString = "0" + minutes; else timeString = String.valueOf(minutes); if (seconds < 10) timeString += ":0" + seconds; else timeString += ":" + seconds; return timeString; } public void run() { running = true; startTime = System.currentTimeMillis(); while (running) { // Zeitspanne im Fenster anzeigen: // direkter Aufruf ist gefährlich, weil Swing-Komponenten // nur aus einem Thread (dem Event-Thread) heraus benutzt // werden dürfen. // mem.drawCurrentTimeString(getTimeString()); // So ist es richtig:den Aufruf in ein Runnable-Objekt kapseln // und an den Event-Thread übergeben. Dieser ruft die run-Methode // des Objekts auf, sobald keine anderen Events mehr zu verarbeiten // sind. SwingUtilities.invokeLater( new Runnable() { public void run () { mem.drawCurrentTimeString(getTimeString()); } } ); // Fuer 1000 ms warten try { Thread.sleep(1000); } catch (InterruptedException e) { } } } public void stopIt() { running = false; } }
Generiert mit Camelot | Probleme mit Camelot? | Geändert am: 27.05.2005