Euer Kommentar ist gefragt!

macsx

Mitglied
Sers!

Also ich hab mal sozusagen "freischnauze" TicTacToe zammengezimmert!

Funktionieren tut's! Vielleicht möchte sich das der Eine oder Andere anschauen und seine Beurteilung darüber abgeben! Es gibt bestimmt noch da und dort ne Verbesserung oder eine Vereinfachung.
Mich würde vor allen Dingen eure Meinung zum EventHandling interessieren!
Ich bin für jede vernünftige Meinung/Diskussion offen!

Ist bestimmt auch keine Studienaufgabe oder Ähnliches, VERSPROCHEN@Thomas Darimont&Friends ^^

Klasse TVorView.java
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * TVorView.java
 * Diese Klasse ist ds erste sichtbare Fenster im Spiel.
 * Spieler muss entscheidung treffen zwischen "X" oder "O".
 */
public class TVorView extends JFrame {
    
    JButton butX, butO;
    JLabel label;
    JPanel panelOben, panelUnten;
    
    public TVorView () {
        
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        setLayout(new GridLayout(2,1));
        
        butX = new JButton("X");
        butO = new JButton("O");
        butX.addActionListener(new TVorViewEvent());
        butO.addActionListener(new TVorViewEvent());
        
        label = new JLabel("Soll mit \"X\" oder mit \"Y\" begonnen werden?");
        
        panelOben = new JPanel();
        panelOben.add(label);
        add(panelOben);
        
        panelUnten = new JPanel();
        panelUnten.add(butX);
        panelUnten.add(butO);
        add(panelUnten);
        
        setSize(350, 130);
        setVisible(true);
        
    }
    
    public static void main(String[] args) {
        new TVorView();
    }
    
    
    public class TVorViewEvent implements ActionListener {

        // hier wird die Entscheidung des Benutzers gespeichert, ob X oder O beginnen soll
        String strFeld = "";
        // Objekt der Klasse TVorView
        TVorView tvvObj;
       
        public void actionPerformed(ActionEvent ae) {
            
            strFeld = ae.getActionCommand();
            setVisible(false);
            dispose();
            new TView(strFeld);
            
        }

    }
    

}

Klasse TView.java
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * TView.java
 * TView ist das Hauptspielfenster. Hier werden alle optischen Bestandteile des
 * Spiels gebildet und wenn nötig mit EventHandler versehen.
 */

public class TView extends JFrame {
    
    JButton but1, but2, but3, but4, but5, but6, but7, but8, but9, butNeu;
    JTextField jtf, jtfStand;
    JPanel panel, panel2;
    
    // speichert den gegenwertigen Stand also "X" oder "O"
    String feld;
    
    // zwei getrennte Modelklassen, eine für alle O-Felder und eine
    // für alle X-Felder
    TModel tModelX, tModelO;
    
    // Objekt vom EventHandler für die Button - zum anhängen und entfernen
    TTTEventHandler teh = teh = new TTTEventHandler();
    
    public TView() {
        
    }
    
    // bekommt bei der Initialisierung das gewählte Feld übergeben 
    // "O" oder "X"
    public TView (String feld) {
        
        this.feld = feld;
        tModelX = new TModel(this);
        tModelO = new TModel(this);
        
        but1 = new JButton("");
        but2 = new JButton("");
        but3 = new JButton("");
        but4 = new JButton("");
        but5 = new JButton("");
        but6 = new JButton("");
        but7 = new JButton("");
        but8 = new JButton("");
        but9 = new JButton("");
        butNeu = new JButton("neues Spiel");
        
        //Anhängen der EventHandler an alle Buttons
        actionFuerButton();
        
        // das JFrame bekommt ein BorderLayout, in dessen CENTER-Bereich
        // das JPanel panel mit einem GridLayout eingefügt wird und in dessen
        // SOUTH-Bereich kommt ein zweites Panel panel2
        this.setLayout(new BorderLayout());
        
        // Panel mit GridLayout(3,3) und alle 9 Spielfelder eingefügt
        panel = new JPanel();
        panel.setLayout(new GridLayout(3,3));
        panel.add(but1);
        panel.add(but2);
        panel.add(but3);
        panel.add(but4);
        panel.add(but5);
        panel.add(but6);
        panel.add(but7);
        panel.add(but8);
        panel.add(but9);
        
        this.add(panel, BorderLayout.CENTER);
        
        // zweites Panel mit BorderLayout und Button für "neues Spiel" sowie
        // ein JTextField für die Ausgabe bei Gewinn oder Falschspiel
        panel2 = new JPanel();
        panel2.setLayout(new BorderLayout());
        this.add(panel2, BorderLayout.SOUTH);
                
        // JTextField zur Ausgabe von "Gewonnen!" oder Fehlern
        jtf = new JTextField(1);
        panel2.add(jtf, BorderLayout.SOUTH);
        panel2.add(butNeu, BorderLayout.NORTH);
        
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        //Größe und Sichtbarkeit
        setSize(350, 350);
        this.setVisible(true);
        
    }
    
    // diese Methode hängt allen Spielfeldern(JButtons) einen EventHandler an
    public void actionFuerButton() {
                
        but1.addActionListener(teh);
        but2.addActionListener(teh);
        but3.addActionListener(teh);
        but4.addActionListener(teh);
        but5.addActionListener(teh);
        but6.addActionListener(teh);
        but7.addActionListener(teh);
        but8.addActionListener(teh);
        but9.addActionListener(teh);
        butNeu.addActionListener(teh);
        
    }
    
    // diese Methode entfernt die EventHandler von den Spielfeldern (JButtons)
    public void removeAction() {
        but1.removeActionListener(teh);
        but2.removeActionListener(teh);
        but3.removeActionListener(teh);
        but4.removeActionListener(teh);
        but5.removeActionListener(teh);
        but6.removeActionListener(teh);
        but7.removeActionListener(teh);
        but8.removeActionListener(teh);
        but9.removeActionListener(teh);
    }
    
    // diese Methode ändert die Aufschrift der Spielfelder in "O" oder "X"
    public void setButtonText(JButton but,String string) {
        
        JButton tmpBut = but;
        tmpBut.setText(string);
    }
    
   
    
/** 
 * Dieser EventHandler fängt alle Klicks auf die Buttons im JFrameFenster ab.
 * 
 */


class TTTEventHandler implements ActionListener{
    
    
    public void actionPerformed(ActionEvent ae) {
        
        // Wenn Button "neues Spiel" geklickt wurde:
        if (ae.getActionCommand() == "neues Spiel") {
            // neues Spiel
            new TVorView();
            setVisible(false);
            dispose();
        }
        // Falls ein Spielbutton geklickt wurde:
        else {
            // falls dieser schon gebraucht wurde:
            if (ae.getActionCommand() != "") {
                jtf.setText("Bitte klicken Sie ein leeres Spielfeld an!");
            }
            // falls ein gültiger Spielbutton geklickt wurde, muss überprüft
            // werden, welchen String die Variable feld in sich trägt
            // wenn feld == "X" ist der Spieler mit "X" an der Reihe
            // wenn feld == "O" ist der Spieler mit "O" an der Reihe
            else {
                setButtonText((JButton)ae.getSource(), feld);
                if (feld == "X") {
                    // jeder Button wird bei Gebrauch dem Objekt der Klasse
                    // TModel übergeben um dort in einen Vector eingefügt zu werden
                    tModelX.add((JButton)ae.getSource());
                    
                    // nun wird noch geprüft, ob vielleicht schon ein Gewinner
                    // entstanden ist, falls ja, dann wird eine Info im JTextField
                    // ausgegeben
                    if (tModelX.testing()) {
                        jtf.setText("Der Spieler mit \"X\" hat gewonnen!");
                        removeAction(); // entfernt die EventHandler von den Buttons
                    }
                    feld = "O";
                    // s.o.
                } else {
                    tModelO.add((JButton)ae.getSource());
                    if (tModelO.testing()) {
                        jtf.setText("Der Spieler mit \"O\" hat gewonnen!");
                        removeAction();
                    }
                    feld ="X";
                }
                
            }

}}}}

Klasse TModel.java
Code:
import java.util.*;
import javax.swing.*;

public class TModel {
    
    Vector vec;
    TView tViewObj = new TView();
    
    // bekommt ein Objekt von Klasse TView übergeben, damit sie später
    // damit auf alle Spielbuttons zugreifen kann.
    // aussdem wird hier der Vector gebildet.
    public TModel(TView obj) {
        tViewObj = obj;
        vec = new Vector();
    }
    
    // fügt die JButton-Objekte ein
    public void add(JButton jBut) {
        vec.add(jBut);
    }	
    
    // testet ob sich schon eine Reihe aus Buttons mit "O" bzw. "X"
    // gebildet hat
    public boolean testing() {
        // es müssen mindestens 3 Objekte im Vector befinden, damit ein Sieg entstehen kann
        if (vec.size() >= 3) {
            // Kombination 1 - 2 - 3
            if (vec.contains(tViewObj.but1)){
                if (vec.contains(tViewObj.but2)) {
                    if (vec.contains(tViewObj.but3)) {
                        return true;
                    }
                }
                // falls die "but1" schon stimmt wird noch auf Kombination 1 - 4 - 7 gestetet
                else if (vec.contains(tViewObj.but4)) {
                    if (vec.contains(tViewObj.but7)) {
                        return true;
                    }
                }
                else if (vec.contains(tViewObj.but5)) {
                    if (vec.contains(tViewObj.but9)) {
                        return true;
                    }
                }
        } // Ende Kombinationen mit dem 1er Reihe
            
            // Beginn mit 2er Reihe
            if (vec.contains(tViewObj.but2) && vec.contains(tViewObj.but5) &&
                    vec.contains(tViewObj.but8)) {
                return true;
            }
            // Ende mit 2er Reihe
            
            
            // Beginn mit 3er Reihe
            // 3 - 6 - 9
            if (vec.contains(tViewObj.but3)) {
                if (vec.contains(tViewObj.but6)) {
                    if (vec.contains(tViewObj.but9)) {
                        return true;
                    }
                }
                // falls "but3" schon stimmt wird noch auf die Kombination 3 - 5 - 7 getestet
                else if (vec.contains(tViewObj.but5)) {
                    if (vec.contains(tViewObj.but7)) {
                        return true;
                    }
                }
            }
            // Ende 3er Reihe
            
            
            // Beginn 4er Reihe
            if (vec.contains(tViewObj.but4) && vec.contains(tViewObj.but5) && vec.contains(tViewObj.but6)) {
                return true;
            }
            // Ende 4 er Reihe
            
            
            // Beginn 7er Reihe
            if (vec.contains(tViewObj.but7) && vec.contains(tViewObj.but8) && vec.contains(tViewObj.but9)) {
                return true;
            }
            return false;
    }return false;
    }
    

}
 
Zuletzt bearbeitet:
Ich benutze derzeit java 6 se, auf abwärtskompatibilität habe ich jetzt nicht geachtet!

Habs noch schnell Java4-tauglich gemacht!! Musste doa nur die Elemente erst auf ein ContentPane einfügen. Bei Java 6 kann ich die Elemente gleich add´n!

Klasse TVorView.java
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

/**
 * TVorView.java
 * Diese Klasse ist ds erste sichtbare Fenster im Spiel.
 * Spieler muss entscheidung treffen zwischen "X" oder "O".
 */
public class TVorView extends JFrame {
    
    JButton butX, butO;
    JLabel label;
    JPanel panelOben, panelUnten;
    Container contentPane;
    
    public TVorView () {
        
        contentPane = getContentPane();
        setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        contentPane.setLayout(new GridLayout(2,1));
        
        butX = new JButton("X");
        butO = new JButton("O");
        butX.addActionListener(new TVorViewEvent());
        butO.addActionListener(new TVorViewEvent());
        
        label = new JLabel("Soll mit \"X\" oder mit \"Y\" begonnen werden?");
        
        panelOben = new JPanel();
        panelOben.add(label);
        contentPane.add(panelOben);
        
        panelUnten = new JPanel();
        panelUnten.add(butX);
        panelUnten.add(butO);
        contentPane.add(panelUnten);
        
        setSize(350, 130);
        setVisible(true);
        
    }
    
    public static void main(String[] args) {
        new TVorView();
    }
    
    
    public class TVorViewEvent implements ActionListener {

        // hier wird die Entscheidung des Benutzers gespeichert, ob X oder O beginnen soll
        String strFeld = "";
        // Objekt der Klasse TVorView
        TVorView tvvObj;
       
        public void actionPerformed(ActionEvent ae) {
            
            strFeld = ae.getActionCommand();
            setVisible(false);
            dispose();
            new TView(strFeld);
            
        }

    }
    

}

Klasse TView.java:
Code:
import javax.swing.*;
import java.awt.*;
import java.awt.event.*;

/**
 * TView.java
 * TView ist das Hauptspielfenster. Hier werden alle optischen Bestandteile des
 * Spiels gebildet und wenn nötig mit EventHandler versehen.
 */

public class TView extends JFrame {
    
    JButton but1, but2, but3, but4, but5, but6, but7, but8, but9, butNeu;
    JTextField jtf, jtfStand;
    JPanel panel, panel2;
    
    Container contentPane;
    
    // speichert den gegenwertigen Stand also "X" oder "O"
    String feld;
    
    // zwei getrennte Modelklassen, eine für alle O-Felder und eine
    // für alle X-Felder
    TModel tModelX, tModelO;
    
    // Objekt vom EventHandler für die Button - zum anhängen und entfernen
    TTTEventHandler teh = teh = new TTTEventHandler();
    
    public TView() {
        
    }
    
    // bekommt bei der Initialisierung das gewählte Feld übergeben 
    // "O" oder "X"
    public TView (String feld) {
        
        this.feld = feld;
        tModelX = new TModel(this);
        tModelO = new TModel(this);
        
        contentPane = getContentPane();
        
        but1 = new JButton("");
        but2 = new JButton("");
        but3 = new JButton("");
        but4 = new JButton("");
        but5 = new JButton("");
        but6 = new JButton("");
        but7 = new JButton("");
        but8 = new JButton("");
        but9 = new JButton("");
        butNeu = new JButton("neues Spiel");
        
        //Anhängen der EventHandler an alle Buttons
        actionFuerButton();
        
        // das JFrame bekommt ein BorderLayout, in dessen CENTER-Bereich
        // das JPanel panel mit einem GridLayout eingefügt wird und in dessen
        // SOUTH-Bereich kommt ein zweites Panel panel2
        contentPane.setLayout(new BorderLayout());
        
        // Panel mit GridLayout(3,3) und alle 9 Spielfelder eingefügt
        panel = new JPanel();
        panel.setLayout(new GridLayout(3,3));
        panel.add(but1);
        panel.add(but2);
        panel.add(but3);
        panel.add(but4);
        panel.add(but5);
        panel.add(but6);
        panel.add(but7);
        panel.add(but8);
        panel.add(but9);
        
        contentPane.add(panel, BorderLayout.CENTER);
        
        // zweites Panel mit BorderLayout und Button für "neues Spiel" sowie
        // ein JTextField für die Ausgabe bei Gewinn oder Falschspiel
        panel2 = new JPanel();
        panel2.setLayout(new BorderLayout());
        contentPane.add(panel2, BorderLayout.SOUTH);
                
        // JTextField zur Ausgabe von "Gewonnen!" oder Fehlern
        jtf = new JTextField(1);
        panel2.add(jtf, BorderLayout.SOUTH);
        panel2.add(butNeu, BorderLayout.NORTH);
        
        this.setDefaultCloseOperation(EXIT_ON_CLOSE);
        
        //Größe und Sichtbarkeit
        setSize(350, 350);
        this.setVisible(true);
        
    }
    
    // diese Methode hängt allen Spielfeldern(JButtons) einen EventHandler an
    public void actionFuerButton() {
                
        but1.addActionListener(teh);
        but2.addActionListener(teh);
        but3.addActionListener(teh);
        but4.addActionListener(teh);
        but5.addActionListener(teh);
        but6.addActionListener(teh);
        but7.addActionListener(teh);
        but8.addActionListener(teh);
        but9.addActionListener(teh);
        butNeu.addActionListener(teh);
        
    }
    
    // diese Methode entfernt die EventHandler von den Spielfeldern (JButtons)
    public void removeAction() {
        but1.removeActionListener(teh);
        but2.removeActionListener(teh);
        but3.removeActionListener(teh);
        but4.removeActionListener(teh);
        but5.removeActionListener(teh);
        but6.removeActionListener(teh);
        but7.removeActionListener(teh);
        but8.removeActionListener(teh);
        but9.removeActionListener(teh);
    }
    
    // diese Methode ändert die Aufschrift der Spielfelder in "O" oder "X"
    public void setButtonText(JButton but,String string) {
        
        JButton tmpBut = but;
        tmpBut.setText(string);
    }
    
   
    
/** 
 * Dieser EventHandler fängt alle Klicks auf die Buttons im JFrameFenster ab.
 * 
 */


class TTTEventHandler implements ActionListener{
    
    
    public void actionPerformed(ActionEvent ae) {
        
        // Wenn Button "neues Spiel" geklickt wurde:
        if (ae.getActionCommand() == "neues Spiel") {
            // neues Spiel
            new TVorView();
            setVisible(false);
            dispose();
        }
        // Falls ein Spielbutton geklickt wurde:
        else {
            // falls dieser schon gebraucht wurde:
            if (ae.getActionCommand() != "") {
                jtf.setText("Bitte klicken Sie ein leeres Spielfeld an!");
            }
            // falls ein gültiger Spielbutton geklickt wurde, muss überprüft
            // werden, welchen String die Variable feld in sich trägt
            // wenn feld == "X" ist der Spieler mit "X" an der Reihe
            // wenn feld == "O" ist der Spieler mit "O" an der Reihe
            else {
                setButtonText((JButton)ae.getSource(), feld);
                if (feld == "X") {
                    // jeder Button wird bei Gebrauch dem Objekt der Klasse
                    // TModel übergeben um dort in einen Vector eingefügt zu werden
                    tModelX.add((JButton)ae.getSource());
                    
                    // nun wird noch geprüft, ob vielleicht schon ein Gewinner
                    // entstanden ist, falls ja, dann wird eine Info im JTextField
                    // ausgegeben
                    if (tModelX.testing()) {
                        jtf.setText("Der Spieler mit \"X\" hat gewonnen!");
                        removeAction(); // entfernt die EventHandler von den Buttons
                    }
                    feld = "O";
                    // s.o.
                } else {
                    tModelO.add((JButton)ae.getSource());
                    if (tModelO.testing()) {
                        jtf.setText("Der Spieler mit \"O\" hat gewonnen!");
                        removeAction();
                    }
                    feld ="X";
                }
                
            }

}}}}


Klasse TModel.java:
Code:
import java.util.*;
import javax.swing.*;

public class TModel {
    
    Vector vec;
    TView tViewObj = new TView();
    
    // bekommt ein Objekt von Klasse TView übergeben, damit sie später
    // damit auf alle Spielbuttons zugreifen kann.
    // aussdem wird hier der Vector gebildet.
    public TModel(TView obj) {
        tViewObj = obj;
        vec = new Vector();
    }
    
    // fügt die JButton-Objekte ein
    public void add(JButton jBut) {
        vec.add(jBut);
    }	
    
    // testet ob sich schon eine Reihe aus Buttons mit "O" bzw. "X"
    // gebildet hat
    public boolean testing() {
        // es müssen mindestens 3 Objekte im Vector befinden, damit ein Sieg entstehen kann
        if (vec.size() >= 3) {
            // Kombination 1 - 2 - 3
            if (vec.contains(tViewObj.but1)){
                if (vec.contains(tViewObj.but2)) {
                    if (vec.contains(tViewObj.but3)) {
                        return true;
                    }
                }
                // falls die "but1" schon stimmt wird noch auf Kombination 1 - 4 - 7 gestetet
                else if (vec.contains(tViewObj.but4)) {
                    if (vec.contains(tViewObj.but7)) {
                        return true;
                    }
                }
                else if (vec.contains(tViewObj.but5)) {
                    if (vec.contains(tViewObj.but9)) {
                        return true;
                    }
                }
        } // Ende Kombinationen mit dem 1er Reihe
            
            // Beginn mit 2er Reihe
            if (vec.contains(tViewObj.but2) && vec.contains(tViewObj.but5) &&
                    vec.contains(tViewObj.but8)) {
                return true;
            }
            // Ende mit 2er Reihe
            
            
            // Beginn mit 3er Reihe
            // 3 - 6 - 9
            if (vec.contains(tViewObj.but3)) {
                if (vec.contains(tViewObj.but6)) {
                    if (vec.contains(tViewObj.but9)) {
                        return true;
                    }
                }
                // falls "but3" schon stimmt wird noch auf die Kombination 3 - 5 - 7 getestet
                else if (vec.contains(tViewObj.but5)) {
                    if (vec.contains(tViewObj.but7)) {
                        return true;
                    }
                }
            }
            // Ende 3er Reihe
            
            
            // Beginn 4er Reihe
            if (vec.contains(tViewObj.but4) && vec.contains(tViewObj.but5) && vec.contains(tViewObj.but6)) {
                return true;
            }
            // Ende 4 er Reihe
            
            
            // Beginn 7er Reihe
            if (vec.contains(tViewObj.but7) && vec.contains(tViewObj.but8) && vec.contains(tViewObj.but9)) {
                return true;
            }
            return false;
    }return false;
    }
    

}
 
Zuletzt bearbeitet:
- Felder private machen
- TModel: TView tViewObj = new TView(); verschwendet Speicherplatz, weil tViewObj im Konstruktor korrekt zugewiesen wird. Einfach Deklaration reicht aus.
- Ein Modell sollte keine JButtons bekommen, denn die Buttons gehören nur zur View. Wenn du das ganze schon separieren willst dann musst du dir da was anderes überlegen
- Ein Vector ist verdammt langsam. Eine ArrayList wäre schneller
- TTTEventHandler teh = teh = new TTTEventHandler(); ? Warum teh = teh?
- public TView(String feld) Nimm mal möglichst viel aus dem Konstruktor raus und pack es in eine Methode init. Es ist immer unübersichtlich wenn im Konstruktor viel drin steht.
- if (ae.getActionCommand() == "neues Spiel") { Strings vergleicht man mit equals!
- setButtonText: Die zuweiseung an tmpBut ist unnötig. Setzte doch direkt den Text auf but
- class TTTEventHandler implements ActionListener.. ist eigentlich nicht nötig. Mach doch lieber: public class TView extends JFrame implements ActionListener { dann brauchst du die innere Klasse nicht.

Benutze mal Findbugs. Damit findest du sicher noch ein paar andere Problemstellen die ich nun so auf die schnelle nicht gesehen habe.
 
Erstmal danke für die Mühe und Zeit das durchzuschauen!

- TTTEventHandler teh = teh = new TTTEventHandler(); ? Warum teh = teh?
Ist natürlich ein Schreibfehler meinerseits, wundert mich selbst, dass das beim kompilen noch nicht beanstandet wurde!

- TModel: TView tViewObj = new TView(); verschwendet Speicherplatz, weil tViewObj im Konstruktor korrekt zugewiesen wird. Einfach Deklaration reicht aus.
Das ist ein Überbleibs´l aus dem ersten Konzept, hab ich vergessen zu löschen.


Ich nehm mir die Verbesserungen zu Herzen. Danke nochmal!
 
Zurück