Return aus einem ActionListener bzw. Werte aus Dialogwahl an mainFrame

Muhkuh42

Grünschnabel
Hallo,

bin heute erst auf dieses Forum gestoßen und habe schon einige Tips anwenden können, aber mit meinem jetzigen Problem komm ich (auch mit der Forumssuche) nicht weiter:

Ich versuche ein 4x4 Sudoku zu bauen und habe einen mainFrame mit JButtons erstellt, klickt man nun auf einen solchen öffnet sich ein Dialog mit den Auswahlzahlen (wiederum Buttons) klickt man diese soll das Dialogfeld sich schließen (das klappt auch noch) und die Zahl dann im mainFrame übernommen werden. Realisiert habe ich das ersteinmal für das obere linke Feld (0,0). Nun kehrt aber meine aufgerufene Methode nicht wieder an die Aufrufstelle zurück - was hab ich da falsch gemacht ? Denn bei erneutem klicken wechselt das Image auf dem Button sofort.

PS: Bin blutiger Anfänger, also bitte nicht so kompliziert antworten und nicht über den Programmierstil kaputtlachen ;-)

Hier noch mein Code (hoffentlich ist es nicht zu viel zum lesen, aber das Meiste ist eh nur Layout):

Anhang anzeigen 27110attachment.java

Vielen Dank im Voraus,

Muhkuh42
 
Ich mache mir gerade mal die Mühe deinen Code zu verbessern damit du lernst einigermaßen ordentlichen Code zu schreiben. Dauert allerdings noch ne Weile.
 
So ein paar Anmerkungen zu deinem Code:
Java:
class Fenster implements ActionListener {
	static JFrame mainFrame = new JFrame();
        JButton z0s0 = new JButton("", eins);

	JButton z0s1 = new JButton("", zwei);

	JButton z0s2 = new JButton("", blank);
        void fenster() { ...}
}

Du möchtest einen JFrame darstellen. Am Einfachen wäre es daher ein extends JFrame zu benutzen statt des mainFrame Feldes.

Weiterhin solltest du einen Konstruktor benutzen. Ein Konstruktor heisst genauso wie die Klasse, hat aber keinen Rückgabetyp. Der Konstruktor hier wäre also:
Java:
public Fenster(){...}

Die ganzen Buttons brauchst du nicht als Felder anzulegen, da es nicht nötigt ist global in der Klassen auf diese zuzugreifen. In meinem Beispiel habe ich die einzelnen Zeilen mit den Buttons in einer Methode mit einer Schleife erstellen lassen. Das ist viel kürzer und besser lesbar als alle von Hand zu erstellen.

Java:
class Zahlauswahl extends JDialog implements ActionListener {
	
	JDialog Auswahl = new JDialog();

	void zahlAuswaehlen() {...}

Warum extendest du den JDialog ohne dieses Feature zu nutzen? Du legst dir ein Feld vom Typ JDialog an welches du nutzt obwohl du schon selber ein JDialog bist. Das ist überflüssig.

Un immer dran denken: Variablennamen werden klein geschrieben, also auswahl statt Auswahl.

Anonyme ActionListener wie ich sie unten verwendet habe sind oft besser lesbar als ein implements ActionListener.

Achja: Immer private benutzen wenn es nicht nötig ist eine höhere Sichtbarkeitsstufe zu haben.

Wenn du noch mehr Fragen hast, dann frag ruhig.

Java:
package de.tutorials;

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

import javax.swing.BoxLayout;
import javax.swing.Icon;
import javax.swing.ImageIcon;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.WindowConstants;

class Sudoku extends JFrame {

	// Start und Endzeit für das Spiel
	private long startz = 0;
	private long endez = 0;

	// Array der auswählbaren Zahlen für Auswahldialog
	private static final String[] numbers = new String[4];
	static {
		for (int i = 0; i < numbers.length; i++) {
			numbers[i] = Integer.toString(i);
		}
	}
	// Icons für die Zahlen
	private static final Icon[] icons = new Icon[5];
	static {
		icons[0] = new ImageIcon("src/de/tutorials/blank.gif");
		icons[1] = new ImageIcon("src/de/tutorials/eins.gif");
		icons[2] = new ImageIcon("src/de/tutorials/zwei.gif");
		icons[3] = new ImageIcon("src/de/tutorials/drei.gif");
		icons[4] = new ImageIcon("src/de/tutorials/vier.gif");
	}

	/**
	 * Konstruktor: Erstellt ein neues Sudoku Spiel
	 */
	public Sudoku() {
		setSize(300, 300);
		// zentriert den Frame auf dem Bildschirm
		setLocationRelativeTo(new JFrame( ));
		setTitle("S - u - d - o - k - u ");
		setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
		init( );
	}

	/**
	 * initialisiert das Spielfeld
	 */
	private void init() {
		Container contentPane = this.getContentPane( );

		contentPane
				.setLayout(new BoxLayout(getContentPane( ), BoxLayout.Y_AXIS));

		// Zeilen für das Spiel erstellen
		JPanel row1 = createRow( );
		JPanel row2 = createRow( );
		JPanel row3 = createRow( );
		JPanel row4 = createRow( );

		// Unterer Teil des Spielfeldes mit Start und End Buttons
		JPanel south = new JPanel( );
		JButton start = new JButton("START");
		// Anonymer actionListener für das drücken auf den Startbutton
		start.addActionListener(new ActionListener( ) {

			public void actionPerformed(ActionEvent arg0) {
				startz = System.currentTimeMillis( );
			}

		});

		JButton ende = new JButton("FERTIG");
		ende.addActionListener(new ActionListener( ) {

			public void actionPerformed(ActionEvent arg0) {
				endez = System.currentTimeMillis( );
				long punkte = 1000000 - (endez - startz);
				Highscore high = new Highscore( );
				high.showHighscore(punkte);
			}

		});
		south.add(start);
		south.add(ende);

		// Elemente dem Frame hinzufügen
		contentPane.add(row1);
		contentPane.add(row2);
		contentPane.add(row3);
		contentPane.add(row4);
		contentPane.add(south);
	}

	/**
	 * Erstellt eine Zeile mit 4 Buttons
	 * 
	 * @return Das Panel mit 4 Buttons
	 */
	private JPanel createRow() {
		JPanel row = new JPanel( );
		row.setLayout(new BoxLayout(row, BoxLayout.X_AXIS));
		for (int i = 0; i < 4; i++) {
			final JButton col = new JButton( );
			// Beim drücken auf den Button Auswahldialog für die
			// Zahlen anzeigen
			col.addActionListener(new ActionListener( ) {

				public void actionPerformed(ActionEvent arg0) {
					String s = (String) JOptionPane.showInputDialog(
							Sudoku.this, "Wählen sie eine Zahl aus:\n",
							"Zahl auswählen", JOptionPane.PLAIN_MESSAGE, null,
							numbers, "0");

					// Zahl auf den Button setzen
					col.setIcon(icons[Integer.parseInt(s)]);
				}

			});
			// Zufallszahl setzen
			col.setIcon(icons[(int) (Math.random( ) * 4)]);
			// Button der Zeile hinzufügen
			row.add(col);
		}
		return row;
	}

	class Highscore extends JFrame {

		public Highscore() {
			init( );
		}

		private void init() {
			setDefaultCloseOperation(WindowConstants.DISPOSE_ON_CLOSE);
			setSize(300, 60);
			setTitle("Highscore");
			setLocationRelativeTo(new JFrame( ));
			getContentPane( ).setLayout(new FlowLayout(FlowLayout.CENTER));
		}

		/**
		 * Zeigt die Highscoreliste mit den erreichten Punkten an
		 * 
		 * @param punkte
		 *            die erreichten Punkte
		 */
		public void showHighscore(long punkte) {
			JLabel a = new JLabel("Sie haben " + punkte
					+ " Punkte erreicht ");
			getContentPane( ).add(a);
			setVisible(true);
		}
	}

	public static void main(String[] args) {
		Sudoku window = new Sudoku( );
		window.setVisible(true);
	}
}
 
1000 Dank für deine Tips
Hab heute leider keine Zeit mehr genauer drüber zu schauen, aber du hast ja sogar alles noch kommentiert. Ich hoffe einfach mal, daß ich alles verstehe, aber wenn nicht frag ich einfach nochmal.

Also nochmal thx für die Mühen, die du dir damit gemacht hast !
 
Nochmal ich :-)

Vielen dank für deinen informativen Quelltext - hab dabei einige Sachen entdeckt, die ich besser machen kann, allerdings ist mir das noch etwas unklar:
private void init()
{ Container contentPane = this.getContentPane( );
contentPane.setLayout(new BoxLayout(getContentPane( ), BoxLayout.Y_AXIS));

Wofür brauche ich einen Container, hätte ich das Layout nicht direkt setzen können ? Also der frame existiert doch...

Desweiteren hast du mein Problem ja sehr gut umschifft mit dem JOptionPane, da hier kein weiterer ActionListener gebraucht wird, der einen Rückgabewert liefern müsste. Ich würde aber an dieser Stelle das Layout gern selbst bestimmen, und dann müsste ich ja in dem ActionPerformed einen weiteren JDialog kreieren und diesem dann erneut einen ActionListener verpassen. Jetzt ist das Problem ja, daß dieser keinen Wert returnen kann. Hatte das ja schon so realisiert, daß einfach eine Variable geändert wird, aber die wird ja erst geändert, wenn ich was klicke, das Programm läuft aber ja vorher schon weiter und gibt den initialisierten Wert zurück.

Hat da vielleicht jemand noch ne Idee ?
 
Ok, habs dieses Problem jetzt selbst gelöst, aber wahrscheinlich nicht so elegant wie manch anderer hier! Habe einfach meine Icons static gesetzt und aus der ActionPerformed-Methode heraus direkt angesprochen.

Wenn aber jemand noch eine Möglichkeit kennt das besser zu lösen, schreibt ruhig noch...

Thx,

Muh
 
Zurück