Herausfinden, auf welchem Panel des CardLayouts man gerade ist?

Diskutiere Herausfinden, auf welchem Panel des CardLayouts man gerade ist? im Java Basics - Anfänger-Themen Bereich.
P

PinkMuffin

Mir hat sich schon wieder ein Problem mit dem CardLayout aufgetan (evtl sollte man das einfach in der Schule lernen.)
Ich habe einen Button rAntwort, der normalerweise immer das nächste Panel aufrufen soll, außer, man befindet sich bereits auf einem bestimmten Panel, dann soll er genau das machen, was normalerweise bei allen anderen Buttons passiert: Ein User wird erstellt, der Rankingliste hinzugefügt und man kommt auf den Endscreen.
Code:
      rAntwort.addActionListener(new ActionListener()
        {
            @Override
            public void actionPerformed(ActionEvent e)
            {
                if(diesesQuiz.panelStapel.getComponent( 0)==diesesQuiz.fragen.get(3).fragePanel)
                {
                    diesesQuiz.endScreen.punktestand++;

                    diesesQuiz.endScreen.highscoreListe.setText("");
                    // Spieler wird erstellt
                    Spieler spieler1 = new Spieler(diesesQuiz.loginPanel.nutzerEingabe.getText(), diesesQuiz.endScreen.punktestand);
                    diesesQuiz.spielerStände.add(spieler1);
                    for (int i=0; i<diesesQuiz.spielerStände.size(); i++)
                    {
                        diesesQuiz.spielerStände.sort(comp);
                        diesesQuiz.endScreen.highscoreListe.append(diesesQuiz.spielerStände.get(i).name+ "    :     "
                        +diesesQuiz.spielerStände.get(i).score + " P\n");
                    }
                    diesesQuiz.card.show(diesesQuiz.panelStapel, "endscreen");
                }
                else
                    {
                        diesesQuiz.endScreen.punktestand++;
                        diesesQuiz.card.next(diesesQuiz.panelStapel);
                    }
            }
        });
Mein Frage-Array beinhaltet 4 Fragen, also müsste bei Index 3 die letzte Frage sein. Allerdings wird der Code im if nie ausgeführt (ich hab es durch das setText schon etwas ausprobiert). Habe ich in meiner if-Bedingung etwas falsch gemacht? Im Internet habe ich nur gefunden, dass man mit "getComponent(0)" das aktuelle Panel erfragen können sollte. Es kommt auch keine Fehlermeldung, hab im Debugger geguckt, er überspringt die if-Anweisung einfach und geht zum nächsten Panel, dass zufällig halt auch der Endscreen ist, aber ändern tut er nichts.

Hier wäre noch meine Klasse, in der das Array ist und in der alle Panels auf das Panel mit dem CardLayout geaddet werden, falls das was hilft
Code:
    //Fragen werden hinzugefügt und den einzelnen Buttons zugeordnet
        fragen = new ArrayList<Frage>();
        Frage frage1 = new Frage(this,"Wie viele Pflanzen hat Sabrina?","8","3","4","7");
        Frage frage2 = new Frage(this,"In welchem Stockwerk sind die Büros von cortility?","4. Stock","UG","EG","3.Stock");
        Frage frage3 = new Frage(this,"Wie heißt der Hund von Ralf Weinmann?","Zoey","Claudia","Martha","Marley");
        Frage frage4 = new Frage(this,"Welcher dieser Nachnamen ist NICHT doppelt bei Cortility vorhanden?","Möller","Dörr","Nitschke","Krämer");
        fragen.add(frage1);
        fragen.add(frage2);
        fragen.add(frage3);
        fragen.add(frage4);


        //Panel-Stapel bekommt das Layout vorgegeben und nimmt andere Panels auf
        panelStapel = new JPanel();
        card = new CardLayout();
        panelStapel.setLayout(card);
        panelStapel.add(loginPanel, "login");
        panelStapel.add(frage1.fragePanel, "fr1");
        panelStapel.add(frage2.fragePanel, "fr2");
        panelStapel.add(frage3.fragePanel, "fr3");
        panelStapel.add(frage4.fragePanel, "fr4");
        panelStapel.add(endScreen, "endscreen");

        hauptfenster.add(panelStapel);
LG
Lena

Edit: Anstatt "3" ein "diesesQuiz.fragen.size()-1" zu schreiben, hab ich schon ausprobiert und führt zum gleichen Ergebnis.
 
P

PinkMuffin

Ich hab jetzt eben erfahren, dass anscheinend das cardLayout nicht weiß, welches Panel gerade selektiert ist, ich das gerade ausgewählte Panel aber als Instanzvariable speichern kann. Wie soll das aber gehen, wenn ich ja nicht darauf zugreifen kann, welches gerade selektiert ist? Der Button ist ja auf allen Panels drauf, ansonsten könnte ich im Prinzip ein komplett eigenes Panel für die letzte Frage erstellen, aber das kann ja nicht Sinn der Sache sein 😕
 
mihe7

mihe7

Dein Problem ist, dass Du Logik und UI vermischst. CardLayout ist, wie der Name schon sagt, für das Layout (UI) zuständig. Deine Logik muss aber wissen, welche Frage angezeigt werden soll und das UI weist das CardLayout einfach an, die entsprechende "Karte" anzuzeigen.

Abgesehen davon haben Deine Fragen grundsätzlich vier Antworten. Ist das Zufall oder tatsächlich so? Falls dem so ist, dann brauchst Du evtl. gar kein CardLayout, da das Layout für alle Fragen vermutlich identisch ist. In dem Fall bräuchtest Du nur die Inhalte auszutauschen.
 
P

PinkMuffin

Abgesehen davon haben Deine Fragen grundsätzlich vier Antworten. Ist das Zufall oder tatsächlich so? Falls dem so ist, dann brauchst Du evtl. gar kein CardLayout, da das Layout für alle Fragen vermutlich identisch ist. In dem Fall bräuchtest Du nur die Inhalte auszutauschen.
Vielen Dank, ich bin mir allerdings nicht sicher, ob ich deine Antwort 100% verstanden habe. Ich hab einfach meinem Button eine Variable mitgegeben, die hochzählt, wie oft besagter Button schon gedrückt wurde, und sobald er so oft gedrückt wurde, wie es fragen gibt, führt er die if-Anweisung aus, das funktioniert, ob du das mit "Logik" gemeint hattest, weiß ich nicht.
Das mit dem Inhalte austauschen hatte einen Grund, allerdings weiß ich nicht mehr genau welchen (ich glaube, weil dann manche Fragen sich wiederholt haben und ich es nicht so recht geschafft habe, den Array mit Fragen zu verkleinern, ohne dass dadurch Fehler entstanden sind).
 
mihe7

mihe7

Nehmen wir mal z. B. Tic-Tac-Toe. Das kannst Du ganz poplig auf Papier darstellen und mit einem Stift ein X und ein O reinkritzeln, oder auch auf dem Monitor mit schöner Grafik anzeigen und per Maus kann der jeweilige Spieler sein nächstes Feld auswählen. Das ist aber nur die "Benutzerschnittstelle" (UI): einmal besteht die eben aus Papier und Stift, und einmal aus Monitor und Maus.

Unabängig vom UI läuft das Spiel aber gleich ab. Es gibt die gleichen Regeln, z. B. werden von zwei Spielern abwechselnd Felder belegt, ein einmal belegtes Feld kann nicht nochmal belegt werden, der Gewinner wird gleich ermittelt usw. Das ist die Logik des Spiels.

Wenn das nicht sauber getrennt wird, endet es meist in ganz fürchterlichem Code. Zum Beispiel wird versucht, den Zustand des Spiels über UI-Elemente abzubilden. Das sieht bei Tic-Tac-Toe z. B. so aus, dass die Belegung eines Feldes (welcher Spieler welches Feld belegt hat) anhand der Texte des Buttons ermittelt wird. Grauenhaft.

Unter anderem aus diesem Grund ist gerade Anfängern grundsätzlich zu empfehlen, Programme erstmal für die Konsole zu programmieren. D. h. eine Klasse übernimmt die Konsolenein- und -ausgabe (=UI) und eine andere Klasse bzw. mehrere andere Klassen stellen dann die Logik dar.

Wenn Du mal Dein Vorhaben etwas genauer beschreibst (ohne Java/programmiertechnische Dinge), können wir mal gemeinsam einen Entwurf erarbeiten. Ich weiß zwar nicht, wie ich zeitlich dazukomme, aber ggf. springt bestimmt auch gerne wer anders ein, so dass die Antworten nicht allzu lange auf sich warten lassen dürften :)
 
P

PinkMuffin

Okay, das Beispiel leuchtet dann doch ein :) .
Im Prinzip funktioniert(e) das, was ich machen sollte: Ein Quiz, dem beliebig viele Fragen hinzugefügt werden können, mit jeweils 4 Antworten auf eine Frage. Man soll einen Nutzernamen eingeben können, die Fragen durchlaufen und am Ende seine Punktzahl bekommen. Die Highscore-Liste soll automatisch den besten nach ganz oben schreiben.
Vom Konzept her müsste es eigentlich einfach sein, dummerweise habe ich vorher nie mit Swing gearbeitet (wäre Thema in der Schule gewesen, aber dann kam Corona und es wurde gestrichen). Dadurch entstehen mir ständig irgendwelche Fehler, von denen ich nicht einmal weiß, wie man sie nennt und deshalb auch mit Google das ein oder andere Missverständnis habe. 😅
 
mihe7

mihe7

Gut, das heißt, Du brauchst schon mal eine Klasse, die eine Frage und die Antwortmöglichkeiten behandelt (ohne UI). Außerdem brauchst Du eine Klasse für das Quiz. Den Rest brauchen wir zunächst nicht, da kümmern wir uns später drum.

Wie läuft so ein Quiz ab? Man startet ein neues Quiz, dann bekommt man eine Frage nach der anderen gestellt (in zufälliger Reihenfolge, nehme ich an), wobei jede Frage beantwortet werden muss. Das Quiz endet, wenn alle Fragen beantwortet wurden. Richtig?

Das ist aber noch zu ungenau und muss näher betrachtet werden. Sobald das Quiz gestartet wurde und bis zum Ende des Quiz steht immer eine Frage zur Verfügung. Die nächste Frage gibt es, sobald die aktuelle Frage beantwortet wurde. Um die Sache noch etwas zu vereinfachen, könnten wir festlegen, dass ein neu erstelltes Quiz sofort gestartet wird.

Ist der Fragenkatalog ein Teil des Quiz? Nein, das Quiz braucht die Fragen lediglich zu kennen. Es muss den Fragenkatalog aber nicht erzeugen. Apropos Fragenkatalog. Eigene Klasse? Könnte man machen, könnte man aber auch etwas zu over-engineered sehen. Wir können es ja mal bei einer ArrayList belassen.

Wer weiß, wie viele Punkte es auf welche Frage gibt? Könnte man konstant machen: z. B. 1 Punkt je korrekte Antwort. Man könnte die Bewertung aber auch der Frage überlassen. Aber: das Quiz verwaltet den Punktestand.

In dem Zusammenhang: wer entscheidet, ob die Antwort richtig ist? Das Fragen-Objekt.

Du siehst, man kann hier vieles analysieren und in jeder Überlegung entstehen ggf. neue Aspekte, die man sich ansehen muss. Das ist auch alles etwas durcheinander und muss geordnet und zusammengefasst werden.

Das Quiz weiß also, ob es zu Ende gespielt wurde (Game over). Es kennt und verwaltet den Punktestand. Es kennt den Fragenkatalog, die aktuelle Frage und es entscheidet nach einer Antwort des Benutzers, welche Frage als nächstes gespielt wird.

Man könnte also mal so anfangen:

Java:
public class Quiz {
    private List<Frage> katalog;
    private int frageIndex;
    private int punkte;
   
    public Quiz(List<Frage> fragen) {
        katalog = new ArrayList<>(fragen); // Kopie, damit das shuffle nichts am Fragenkatalog ändert.
        Collections.shuffle(katalog);
    }

    public Frage gibAktuelleFrage() {
        return katalog.get(frageIndex);
    }

    public void verarbeiteAntwort(String antwort) {
        punkte += gibAktuelleFrage().bewerte(antwort);
        frageIndex++;
    }

    public boolean isGameOver() {
        return frageIndex >= katalog.size();
    }

    public int gibPunkte() {
        return punkte;
    }
}
Damit Du mal einen Anfang hast. Probier mal, den Spaß auf der Konsole umzusetzen.
 
B

BestGoalkeeper

Ich hätte das vielleicht so auf der Konsole umgesetzt (Fragen und Antworten werden gemischt um die Schwierigkeit zu erhöhen):
Java:
import java.util.ArrayList;
import java.util.Collections;
import java.util.Iterator;
import java.util.List;
import java.util.Scanner;

public class Quiz {
	private ArrayList<ArrayList<String>[]> fragenUndAntworten = new ArrayList<ArrayList<String>[]>();
	private Iterator<ArrayList<String>[]> iterator = null;

	@SuppressWarnings("unchecked")
	public Quiz() {
		fragenUndAntworten.add(new ArrayList[] { 
				new ArrayList<String>(List.of("Wie viele Pflanzen hat Sabrina?")),
				new ArrayList<String>(List.of("8", "3", "4", "7")), 
				new ArrayList<String>(List.of("8")) 
			});
		fragenUndAntworten.add(new ArrayList[] { 
				new ArrayList<String>(List.of("In welchem Stockwerk sind die Büros von cortility?")),
				new ArrayList<String>(List.of("4. Stock", "UG", "EG", "3.Stock")),
				new ArrayList<String>(List.of("UG")) 
			});
		fragenUndAntworten.add(new ArrayList[] { 
				new ArrayList<String>(List.of("Wie heißt der Hund von Ralf Weinmann?")),
				new ArrayList<String>(List.of("Zoey", "Claudia", "Martha", "Marley")),
				new ArrayList<String>(List.of("Marley")) 
			});
		fragenUndAntworten.add(new ArrayList[] {
				new ArrayList<String>(List.of("Welcher dieser Nachnamen ist NICHT doppelt bei Cortility vorhanden?")),
				new ArrayList<String>(List.of("Möller", "Dörr", "Nitschke", "Krämer")),
				new ArrayList<String>(List.of("Dörr")) 
			});
		Collections.shuffle(fragenUndAntworten);
		for (ArrayList<String>[] arrayLists : fragenUndAntworten) {
			Collections.shuffle(arrayLists[1]);
		}
		iterator = fragenUndAntworten.iterator();
	}

	public ArrayList<String>[] nextFrage() {
		return iterator.next();
	}

	public boolean hasNext() {
		return iterator.hasNext();
	}

	@SuppressWarnings("resource")
	public static void main(String[] args) {
		Quiz quiz = new Quiz();
		while (quiz.hasNext()) {
			ArrayList<String>[] frage = quiz.nextFrage();
			System.out.println("Frage: " + frage[0]);
			System.out.println("Antworten von 1 bis 4: " + frage[1]);
			System.out.print("Deine Antwort: ");
			int i = new Scanner(System.in).nextInt();
			int j = -1;
			for (int j2 = 0; j2 < frage[1].size(); j2++) {
				if (frage[1].get(j2).equals(frage[2].get(0))) {
					j = j2;
					break;
				}
			}
			if (i - 1 == j) {
				System.out.println("richtig");
			} else {
				System.out.println("falsch");
			}
		}
	}
}
Aber eine Frage noch... wer oder was ist cortility?
 
P

PinkMuffin

Ich hätte das vielleicht so auf der Konsole umgesetzt (Fragen und Antworten werden gemischt um die Schwierigkeit zu erhöhen):
Java:
import java.util.ArrayList;

    @SuppressWarnings("unchecked")
    public Quiz() {
        fragenUndAntworten.add(new ArrayList[] {
                new ArrayList<String>(List.of("Wie viele Pflanzen hat Sabrina?")),
                new ArrayList<String>(List.of("8", "3", "4", "7")),
                new ArrayList<String>(List.of("8"))
            });

}
Aber eine Frage noch... wer oder was ist cortility?
Das ist eine Sache, die bei mir nie funktioniert.. Dieses "List.of". Ich hab es jetzt an dem Beispiel eins zu eins ausprobiert (und vorher schon mal mit anderen Beispielen), aber der Befehl funktioniert nie, auch diesmal nicht. Ich habe nur die Optionen, die methode umzubenennen, oder einen "on-demand static import for List" zu adden, wodurch aber einfach nur "List" verschwindet und es genauso wenig funktioniert..
Cortility ist die Firma, bei der ich Praktikum mache, von dort kommt auch die Aufgabe.
 
P

PinkMuffin

Gut, das heißt, Du brauchst schon mal eine Klasse, die eine Frage und die Antwortmöglichkeiten behandelt (ohne UI). Außerdem brauchst Du eine Klasse für das Quiz. Den Rest brauchen wir zunächst nicht, da kümmern wir uns später drum.

Ist der Fragenkatalog ein Teil des Quiz? Nein, das Quiz braucht die Fragen lediglich zu kennen. Es muss den Fragenkatalog aber nicht erzeugen. Apropos Fragenkatalog. Eigene Klasse? Könnte man machen, könnte man aber auch etwas zu over-engineered sehen. Wir können es ja mal bei einer ArrayList belassen.
Aber wenn das Quiz die Fragen nicht erzeugt, müssen sie ja in der Startklasse erzeugt, bzw hinzugefügt werden(?).
Käme zwar ungefähr auf das Gleiche raus, nur wurde uns bisher immer gesagt, dass die Startklasse mit der main-methode nur dafür da ist, andere Methoden auszuführen..
 
mihe7

mihe7

Aber wenn das Quiz die Fragen nicht erzeugt, müssen sie ja in der Startklasse erzeugt, bzw hinzugefügt werden(?).
Käme zwar ungefähr auf das Gleiche raus, nur wurde uns bisher immer gesagt, dass die Startklasse mit der main-methode nur dafür da ist, andere Methoden auszuführen..
Das ist auch kein Widerspruch. "Das Quiz" ist im Modell oben eher eine Runde, die ein Spieler nach festen Regeln durchspielt, insbesondere ist "das Quiz" ist nicht das Programm.

Es geht um Verantwortlichkeiten: die Quiz-Klasse ist verantwortlich für den Ablauf des Spiels. Wo die Fragen herkommen, muss das Quiz nicht interessieren. Die Fragen könnten z. B. aus einer Datei oder einer Datenbank gelesen oder über einen Webservice abgerufen werden. Durch die Aufteilung der Zuständigkeiten wird die Anwendung flexibel.

Nehmen wir mal an, die Quiz-Klasse würde die Fragen erzeugen (hart im Code). Jetzt kommt Dein Chef und sagt, ok, neue Aufgabe: lies die Fragen aus einer Datei ein. Dann müsstest Du die Quiz-Klasse ändern. Dann bekommst Du die nächste Aufgabe: lies den Spaß aus einer Datenbank ein. Du gehst her und änderst die Quiz-Klasse wieder ab. Als nächstes heißt es, alle drei Optionen sollen möglich sein. Jetzt müsstest Du hergehen und alles zusammen in die Quiz-Klasse einbauen. Außerdem muss dann eine Unterscheidung im Quiz her, welche Variante verwendet werden soll. Früher oder später entsteht Spaghetti-Code.

Kurz: Deine Quiz-Klasse erhält immer mehr Aufgaben und damit Abhängigkeiten. Irgendwann blickst Du nicht mehr durch oder, noch schlimmer, es entstehen Achsen von Abhängigkeiten durch die Anwendung hindurch und jede Änderung wird zu einem riesigen Problem.

Aus dem Grund trennt man die Zuständigkeiten und übergibt Objekte an das Objekt, das von diesen abhängig ist (nennt sich dann dependency injection). In dem Fall sagen wir einfach: der Fragenkatalog ist eine Sache, die Durchführung des Quiz eine andere. Das Quiz benötigt bei seiner Erzeugung (oder zur Durchführung) einen Fragenkatalog? Soll es haben.
 
B

BestGoalkeeper

Genau, also man muss die Zuständigkeiten trennen.

Hier nur etwas gemein, der Begriff "Quiz" kann sowohl Daten wie Logik beschreiben. ;)

Zur Austauschbarkeit hab ich mir bei ArrayList<ArrayList<String>[]> fragenUndAntworten aber nicht viele Gedanken gemacht...
 
Thema: 

Herausfinden, auf welchem Panel des CardLayouts man gerade ist?

Passende Stellenanzeigen aus deiner Region:
Anzeige

Neue Themen

Anzeige

Anzeige
Oben