Swing Reihenfolge bei ActionListenern

Klösp

Aktives Mitglied
Hallo,

bin wieder dabei mich mit GUIs zu beschäftigen.
Zur Übung wollte ich einfach mal ein kleines Memory basteln.

Dabei bin ich folgendes Problem gestoßen:

Zunächst mal meine Klassen

Das Hauptfenster
Java:
package main;

import java.awt.BorderLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.SwingUtilities;

public class SpielFenster extends JFrame {

	Spielfeld spielfeld;
	JLabel spielstandanzeige;

	public SpielFenster() {
		super.setTitle("Memory");
		super.setBounds(0, 0, 750, 750);
		super.setVisible(true);
		super.setLayout(new BorderLayout());
		this.spielfeld = new Spielfeld();
		super.add(spielfeld, BorderLayout.NORTH);
		this.spielstandanzeige = new JLabel("Spiel läuft");
		this.spielstandanzeige.setSize(100, 100);
		super.add(spielstandanzeige, BorderLayout.SOUTH);
		for (SpielFeldJButton btn : this.spielfeld.buttons.keySet()) {
			btn.addActionListener(new ActionListener() {

				@Override
				public void actionPerformed(ActionEvent arg0) {
					
					if (win()) {
						spielstandanzeige.setText("Gewonnen");
						System.out.println("gewonnen");
					}
					
				}
			});
		}
		super.setDefaultCloseOperation(EXIT_ON_CLOSE);

	}

	public boolean win() {
		for (SpielFeldJButton btn : this.spielfeld.buttons.keySet()) {
			if (!btn.isConsumed()) {
				return false;
			}
		}
		return true;
	}
}

Das Panel mit den Schaltflächen(im Moment noch mit Text)
Java:
package main;


public class Spielfeld extends JPanel {
	HashMap<SpielFeldJButton, String> buttons;

	public Spielfeld() {
		this.buttons = new HashMap<SpielFeldJButton, String>();
		this.initiateSpielfeld(new SpielfeldActionListener(this));

	}

	private void initiateSpielfeld(ActionListener al) {
		super.setSize(500, 500);
		super.setBackground(Color.CYAN);
		super.setLayout(new GridLayout(2, 2));
		super.setVisible(true);

		this.buttons.put(new SpielFeldJButton("Eins"), "Fisch");
		this.buttons.put(new SpielFeldJButton("Zwei"), "Fisch");
		this.buttons.put(new SpielFeldJButton("Drei"), "Affe");
		this.buttons.put(new SpielFeldJButton("Vier"), "Affe");

		for (SpielFeldJButton btn : buttons.keySet()) {
			btn.setVisible(true);
			btn.setSize(200, 200);
			btn.setBackground(Color.BLUE);
			btn.setForeground(Color.WHITE);
			btn.addActionListener(al);

			super.add(btn);
		}
	}
}

Der ActionListener für die Schaltflächen
Java:
package main;

import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JLabel;

public class SpielfeldActionListener implements ActionListener {
	private Spielfeld spielfeld;
	private int counter;
	private SpielFeldJButton firstclicked;
	private SpielFeldJButton secondclicked;

	public SpielfeldActionListener(Spielfeld spielfeld) {
		this.spielfeld = spielfeld;
		counter = 0;
	}

	@Override
	public void actionPerformed(ActionEvent e) {
		
	
		

		if (counter == 0) {
			this.setFirstclicked((SpielFeldJButton) e.getSource());
			this.getFirstclicked().setEnabled(false);
			this.getFirstclicked().setText(
					spielfeld.buttons.get(this.getFirstclicked()));
			counter++;
		} else if (counter == 1) {
			this.setSecondclicked((SpielFeldJButton) e.getSource());
			this.getSecondclicked().setEnabled(false);
			this.getSecondclicked().setText(
					spielfeld.buttons.get(this.getSecondclicked()));
			counter--;
			try {
				Thread.sleep(500);
			} catch (InterruptedException e1) {
				// TODO Auto-generated catch block
				e1.printStackTrace();
			}
		}

		if (spielfeld.buttons.get(this.firstclicked).equals(
				spielfeld.buttons.get(this.secondclicked))
				&& counter != 1) {
			this.getFirstclicked().setText("Päärchen gefunden");
			this.getSecondclicked().setText("Päärchen gefunden");
			this.firstclicked.setConsumed(true);
			this.secondclicked.setConsumed(true);

		} else if (!spielfeld.buttons.get(this.firstclicked).equals(
				spielfeld.buttons.get(this.secondclicked))
				&& counter != 1) {
			this.getFirstclicked().setText("schonmal geklickt");
			this.getSecondclicked().setText("auch schonmal geklickt");
			this.getFirstclicked().setEnabled(true);
			this.getSecondclicked().setEnabled(true);
			
		}
	
		
	}

	public JButton getFirstclicked() {
		return firstclicked;
	}

	public void setFirstclicked(SpielFeldJButton firstclicked) {
		this.firstclicked = firstclicked;
	}

	public JButton getSecondclicked() {
		return secondclicked;
	}

	public void setSecondclicked(SpielFeldJButton secondclicked) {
		this.secondclicked = secondclicked;
	}
	public boolean win() {
		for (SpielFeldJButton btn : this.spielfeld.buttons.keySet()) {
			if (!btn.isConsumed()) {
				return false;
			}
		}
		return true;
	}
}

leicht modifizierter JButton (für die Gewinnbedingung)
Java:
public class SpielFeldJButton extends JButton {
	private boolean consumed;
	
	public SpielFeldJButton(String text){
		super(text);
		this.consumed=false;
	}

	public boolean isConsumed() {
		return consumed;
	}

	public void setConsumed(boolean consumed) {
		this.consumed = consumed;
	}
}


Sorry für den vielen Quelltext, aber ich denke so kann ich mein Problem am besten erklären.

Wenn das initiiert wird (initiateSpielfeld) wird für Buttons der ActionListener registriert, der die Funktionalität regelt.
Dann wird im SpielFenster ein ActionListener registriert, der kontrolliert ob die Gewinnbedingung erfüllt ist.

Das Problem ist nun die Reihenfolge, in der diese vermutlich abgearbeitet werden.
Da der in SpielFenster registrierte ActionListener scheinbar zuerst ausgeführt wird, ist die win() nie wahr. Da ja dann erst später im anderen ActionListener die Buttons auf consumed=true gesetzt werden.

Nach meinen Versuche scheint es mir, als ob der zuletzt registrierte Listener zuerst ausgeführt wird.
Stimmt das?

Falls ja würde ich das Problem in den Griff bekomme, indem ich das Label nicht zum SpielFenster hinzufüge, sondern zum Spielfeld.
Allerdings möchte ich das eigentlich ungern, da das Spielfeld eigentlich auch wirklich nur die Schaltflächen enthalten soll.

Welche anderen möglichkeiten habe ich? (am besten ohne das Klassenmodell groß zu ändern)

Vielen Dank im Vorraus
 

Klösp

Aktives Mitglied
Hallo
hab das Problem jetzt wie folgt gelöst.
(wenn meine Vermutung bzgl. der Reihenfolge richtig war)


Der Klasse Spielfeld wird jetzt das JLabel zum Anzeigen den Spielstatus mit übergeben
Java:
package main;

import java.util.HashMap;
import javax.swing.*;

import java.awt.*;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class Spielfeld extends JPanel {
	HashMap<SpielFeldJButton, String> buttons;
	JLabel spielstandanzeige;

	public Spielfeld(JLabel spielstandanzeige) {
		this.buttons = new HashMap<SpielFeldJButton, String>();
		this.spielstandanzeige=spielstandanzeige;
		this.initiateSpielfeld();

	}

	private void initiateSpielfeld() {
		super.setSize(500, 500);
		super.setBackground(Color.CYAN);
		super.setLayout(new GridLayout(2, 2));
		super.setVisible(true);
		SpielfeldActionListener sal=new SpielfeldActionListener(this);
		ActionListener gewinnListener=new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e) {
				if(win()){
					spielstandanzeige.setText("gewonnen");
				}			
			}
			
		};
		this.buttons.put(new SpielFeldJButton("Eins"), "Fisch");
		this.buttons.put(new SpielFeldJButton("Zwei"), "Fisch");
		this.buttons.put(new SpielFeldJButton("Drei"), "Affe");
		this.buttons.put(new SpielFeldJButton("Vier"), "Affe");

		for (SpielFeldJButton btn : buttons.keySet()) {
			btn.setVisible(true);
			btn.setSize(200, 200);
			btn.setBackground(Color.BLUE);
			btn.setForeground(Color.WHITE);
			btn.addActionListener(gewinnListener);
			btn.addActionListener(sal);

			super.add(btn);
		}
	}
	
	public boolean win() {
		for (SpielFeldJButton btn : this.buttons.keySet()) {
			if (!btn.isConsumed()) {
				return false;
			}
		}
		return true;
	}

}

Das funktioniert scheinbar auch.

Eine Frage hab ich dennoch.


Ich versuche gerade noch einen Button hinzuzufügen, der das ganze Spiel neustartet.
Mein Ansatzt ist folgender (siehe Listener für JButton neustart):
Java:
package main;

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JRootPane;
import javax.swing.SwingUtilities;

public class SpielFenster extends JFrame {

	Spielfeld spielfeld;
	JLabel spielstandanzeige;
	JButton neustart;

	public SpielFenster() {
		super.setTitle("Memory");
		super.setBounds(0, 0, 750, 750);
		super.setVisible(true);
		super.setLayout(new BorderLayout());	
		this.spielstandanzeige = new JLabel("Spiel läuft");
		this.spielstandanzeige.setSize(100, 100);
		super.add(spielstandanzeige, BorderLayout.SOUTH);
		this.spielfeld = new Spielfeld(spielstandanzeige);
		super.add(spielfeld, BorderLayout.NORTH);
		super.setDefaultCloseOperation(EXIT_ON_CLOSE);
		this.neustart=new JButton("Neustart");
		this.neustart.addActionListener(new ActionListener(){
			@Override
			public void actionPerformed(ActionEvent e) {
				JButton btn=(JButton)e.getSource();
				btn.getParent().remove(1);
				btn.getParent().add(new Spielfeld(spielstandanzeige),BorderLayout.NORTH, 1);
				spielstandanzeige.setText("Spiel läuft");
			}			
		});

		super.add(neustart,BorderLayout.CENTER);
	}
}

Das funktioniert zwar auch theoretisch. Das Problem ist allerdings, dass das Fenster die Anzeige nicht immer aktualisiert.
Teilweise nur wenn ich das Fenster einmal minimiere und wieder maximiere.

Wie kann ich das richtig hinbekommen? Wie macht man sowas üblicherweise?


Danke im Vorraus
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
H JavaFX Timeline KeyFrame Reihenfolge AWT, Swing, JavaFX & SWT 6
T Reihenfolge der Komponenten im einem JFrame AWT, Swing, JavaFX & SWT 8
J Reihenfolge der Punkte in Vielecken AWT, Swing, JavaFX & SWT 3
C Swing Reihenfolge der Initialisierung von Komponenten AWT, Swing, JavaFX & SWT 6
GUI-Programmer JFilechooser, mehrere Datein selektieren und Reihenfolge (2) AWT, Swing, JavaFX & SWT 8
T Java-Anwendung arbeitet Programm in seltsamer Reihenfolge ab AWT, Swing, JavaFX & SWT 3
M Komponenten in anderer Reihenfolge anzeigen AWT, Swing, JavaFX & SWT 4
lumo LayoutManager SWT GridLayout - Reihenfolge ändern AWT, Swing, JavaFX & SWT 7
P Swing Hierachie oder Reihenfolge von Komponenten AWT, Swing, JavaFX & SWT 5
C Swing Text eines JButton mit String definieren? Reihenfolge? AWT, Swing, JavaFX & SWT 6
D Swing JOptionPane + FileChooser .. Reihenfolge wichtig!? AWT, Swing, JavaFX & SWT 7
A Reihenfolge von ActionListener und InputVerifier AWT, Swing, JavaFX & SWT 4
P JList: Reihenfolge der Elemente per Drag'n'Drop ändern. AWT, Swing, JavaFX & SWT 9
T Tab Reihenfolge bei JTextFeldern ändern AWT, Swing, JavaFX & SWT 4
H Reihenfolge z.B. KeyPressed in Child/Parent AWT, Swing, JavaFX & SWT 11
G Reihenfolge von Events AWT, Swing, JavaFX & SWT 4
S Labels und Button übereinander --> Reihenfolge? AWT, Swing, JavaFX & SWT 4
M Tab-Reihenfolge aber mit SWT AWT, Swing, JavaFX & SWT 1
K Tab-Reihenfolge AWT, Swing, JavaFX & SWT 7
T "globaler" keylistener/tab-reihenfolge/insertcurso AWT, Swing, JavaFX & SWT 5
B JTree - Reihenfolge der Nodes verändern AWT, Swing, JavaFX & SWT 3
N Fokus Reihenfolge ändern AWT, Swing, JavaFX & SWT 12
bernd Reihenfolge beim springen mit Tab-Taste ändern! AWT, Swing, JavaFX & SWT 4
D Frage zu ActionListenern und AvtionEvents AWT, Swing, JavaFX & SWT 2
G Problem mit ActionListenern bei Buttons AWT, Swing, JavaFX & SWT 3
C Frage zu ActionListenern AWT, Swing, JavaFX & SWT 7

Ähnliche Java Themen


Oben