Klasse über Button Event in anderer Klasse informieren

robC

Mitglied
Hallo!

Ich habe bereits einige Zeit in Google und Co investiert und habe nichts passendes gefunden. Deshalb habe ich mich entschlossen, mich hier anzumelden und meine Problematik direkt zu erläutern.

Für ein Schulprojekt programmiere ich in einer kleinen Gruppe ein Spiel. Das Spiel an sich läuft super, keine Probleme.
Dummerweise kommen die Probleme nun bei dem Bereich, der uns eigentlich viel trivialer vorkam, dem Programmieren eines Hauptmenüs.

Wir haben uns überlegt, das ganze in einem
Code:
JFrame
zu programmieren und in diesem
Code:
JFrame
zwischen verschiedenen
Code:
JPanel
zu wechseln, um das Projekt später vielleicht auch einfach in ein Applet packen zu können.
Das heißt, wir haben eine Klasse
Code:
SwitchPanel
und viele von
Code:
JPanel
abgeleitete Klassen, die wir je nach Bedarf zu unserem
Code:
JFrame
hinzufügen.
Zwei Klassen sind zum Beispiel
Code:
Hauptmenu
und
Code:
Spiel
.

Außerdem gibt es die Klasse
Code:
Spielfluss
, welche eigentlich den Wechsel zwischen den einzelnen Panels aufgrund von diversen Events (zum Beipiel einem Klick auf einen Button oder dem Ende des Spiels) ausführt.

Hier kommt das Problem:
Eine Instanz der Klasse
Code:
Spielfluss
instanziert die Klasse
Code:
Hauptmenu
, welche wie gesagt von
Code:
JPanel
abgeleitet ist,
Code:
ActionListener
implementiert und verschiedene Buttons besitzt. Ein Button ist zum Beispiel mit "Spiel starten" beschriftet, ein anderer mit "Optionen" usw.
Diese Buttons sind mit dem klasseneigenen
Code:
ActionListener
verbunden und bei einem Klick geben sie zur Zeit noch ihre Beschriftung in der Konsole aus, ohne eine weitere Bedeutung zu haben.
Allerdings passiert das alles nur in der Instanz von
Code:
Hauptmenu
, wir brauchen die Info über ein ActionEvent und vor allem, welcher Button gedrückt wurde, aber in der Instanz von
Code:
Spielfluss
.

Hat jemand eine Ahnung, wie das geht, bzw. geblickt, was ich meine? Sorry, ist ein wenig viel, aber ich dachte ich schreibe lieber zu viel als zu wenig 😉

Hier noch eine Grafik, die meinen Gedankengang beschreiben soll:
spielfluss-hauptmenu-grafik.png


Grüße und Danke im Voraus,
Roberto
 
Zuletzt bearbeitet:
Ihr könntet den anderen Klassen beim Start (das übernimmt Spielfluss?) die Instanz (this) des Spielflusses mitgeben, welche ihr da (vielleicht nur als vereinfachtes Interface) vorhaltet und dann beim auftretenden Events an die Spielflussklasse weiterreicht.

Spielfluss hat ja z.B. das Hauptmenü erstellt, kennt es also und kann diesem (Objekt vorhalten) dann auch sagen (dort Methoden aufrufen), dass etwas bestimmtes eingetreten ist.

Ich hoffe ich hab das Problem verstanden.
 
Zuletzt bearbeitet von einem Moderator:
Hallo und danke für die flotten Antworten!

@Crian:
Das mit dem Übergeben der Klasse an die anderen Klassen erscheint mir plausibel. Meinst du, ich soll dann von z.B. Hauptmenu eine Methode in Spielfluss aufrufen, die das Event weiterverarbeiten kann? Außerdem verstehe ich die Anmerkung in der Klammern nicht ganz bezüglich des vereinfachten Interface. Was genau meinst du damit? (Was ein Interface ist weiß ich, habe aber noch nie wirklich damit gearbeitet und weiß dementsprechend nicht, was ich damit in diesem Fall anfangen soll)

@Tomate_Salat:
Das mit dem CardLayout scheint wohl eine fertige Klasse zu sein, die wir ansatzweise für unser Projekt schon selbst geschrieben haben... Mal wieder ein Schlag ins Gesicht 😀 Aber trotzdem danke, vielleicht bauen wir's noch ein!
Die anderen Hinweise / Links sind sehr interessant, ich werde mir die Konzepte und Klassen mal genauer anschauen 🙂

Sobald ich die bisherigen Hinweise und Tipps näher geprüft und nachvollzogen habe, melde ich mich wieder! Vielen vielen Dank nochmal für die schnellen und hilfreichen Antworten!

Güße,
Roberto
 
Ich hab für eine grafische Oberflächen auch die Lösung genommen, die Verwalterklasse (dein Spielfluss) an die anderen weiterzugeben. Die speichern diese aber nicht als Spielfluss-Klasse, sondern als Ausprägung eines Interfaces. D.h. das Objekt dahinter ist natürlich die Spielflussklasse, aber die anderen Klassen müssen darüber nicht mehr wisse, als dass es ein paar Methoden gibt, die sie aufrufen können (und welche im Interface beschrieben sind).

Das ist für dieses Projekt vielleicht unnötig, aber es hilft zur Entkopplung.
 
Das wäre dann etwa so:

Java:
interface Verwaltung {

    public void tuWas();

}

Java:
class Spielfluss implements Verwaltung {

    private Hauptmenue hauptmenue;

    public Spielfluss() {
        hauptmenue = new Hauptmenue(this);
    }

    // ...

    @Override
    public void tuWas() {
        // ...
        hauptmenue.reagiere();
    }

}

Java:
class Hauptmenue {

    private Verwaltung verwaltung;

    public Hauptmenue(Verwaltung verwaltung) {
        this.verwaltung = verwaltung;
    }


    // ....
        verwaltung.tuWas();
    // ...

    public void reagiere() {
        // ...
    }

}

Edit: Man kann das jetzt auch noch weiter entkoppeln und bis auf die Erstellung das hauptmenue-Objekt im Spielfluss als eine Instanz eines Interfaces ablegen, das nur "reagiere" kennt, aber das würde das ganze jetzt vielleicht ein wenig überfrachten.
 
Zuletzt bearbeitet:
Hallo Crian!

Ich habe mir das jetzt folgendermaßen überlegt gehabt, bevor du den Code gepostet hast:

spielfluss-hauptmenu-crian.png


Frage: Wozu brauche ich das Interface? So wie du das beschrieben hast erscheint es mir nicht ganz schlüssig bzw. sinnvoll. Schließlich überschreibst du die Methode der Verwaltungsklasse lediglich mit einem Methodenaufruf der Klasse
Code:
Hauptmenu
. Kann ich die Methode nicht auch einfach so aurufen, sobald ein ActionEvent registriert wurde? (siehe Grafik)

Grüße und Danke,
Roberto
 
Es geht darum, Abhängigkeiten zu vermeiden (wobei ich das Interface nicht über den Konstruktor sondern über eine add* oder set* Methode registrieren würde). Durch dieses Interface müssen sich die beiden Klasse nicht direkt kennen. Es reicht, wenn die eine Klasse weis, welche Methode Sie aufrufen muss und über Interface ist gewährleistet, dass diese vorhanden und implementiert wurde. Dadurch kannst du "einfach" Klassen austauschen (siehe MVC-Pattern).
 
Zur Lösung des Problems direkt trägt die Verwendung eines Interfaces nicht bei das stimmt, aber wenn du, wie TomateSalat sagt, die Klasse austauschen willst, dann musst du nicht erst recherchieren, was alles verwendet wird (denn das steht schon im Interface), sondern musst nur drauf achten, dass die neue Klasse das Interface implementiert.

Ja über einen Setter ginge es natürlich auch. Ich wollte das ganze erstmal einfach halten. 🙂

Du musst es für dieses Spiel ja nicht so machen, dann schreibst du überall statt Verwaltung Spielfluss hin und fertig.


Im Spielfluss brauchst du keine Methode actionPerformed. Du kannst sie natürlich so nennen, aber meist macht man da ja speziellere Sachen. Hat also nicht eine tuWas()-Methode, sondern mehrere unterschiedliche für verschiedene Aufgaben.

So kann man auch die Logik von der Oberfläche trennen, etwa um Dateioperationen nicht mitten im Gui-Code stehen zu haben.
 
Zuletzt bearbeitet:
Die Erklärung klang IMHO sinnvoll und war gut und ausführlich, aber... wie das so ist 😉 ... für mich noch nicht ausführlich genug.

"Spielfluss" steuert quasi ein "SwitchPanel", und schaltet zwischen den Panels hin und her. Wie genau ist denn jetzt die Beziehung zwischen dem "Hauptmenu" und dem "Spielfluss" (wer erstellt wen, wer steuert wen...?)

Ganz subjektiv finde ich so ein Weiterreichen von ActionEvents nicht so schön. In welchen Fällen muss eine Nachricht (d.h. ein ActionEvent) vom Spielfluss-Panel an das Hauptmenü (oder umgekehrt?) weitergereicht werden?
 
Hallo!

Hab's jetzt so gemacht und funktioniert super! Vielen Dank für die ausführliche Erklärung.

Grüße und schönen Tag noch,
Roberto

P.S. @Tomate_Salat:
Deine Tipps werde ich mir noch genauer anschauen, brauchte jetzt aber eine schnelle und unkomplizierte Lösung, da ich bis Ende des Schuljahres fertig sein muss und mich auch noch mit meinem mündlichen Abi beschäftigen muss. Trotzdem vielen Dank!
 
Marco13
Vielleicht hilft dir diese Grafik weiter:
spielfluss-hauptmenu-marco13.png


SpielFluss
Hat keine grafische Oberfläche sondern steuert den Spielablauf, also z.B. ruft das Hauptmenu am Anfang auf, startet das Spiel, sobald der Button im Hauptmenu gedrückt wurde, beendet das Spiel, sobald der Held gestorben ist, etc.

SwitchPanel
Ist im Prinzip ein Rahmen der von JFrame abgeleitet ist und alle Spielelemente beinhaltet (Das grafische Hauptmenü, die Spieloberfläche, eine Oberfläche, mit der Optionen gesetzt werden können, etc.

Hauptmenu, Spiel, Optionen
Sind von JPanel abgeleitet, beinhalten ihrerseits wieder Components, beispielsweise JButtons, JPanels, etc. und werden je nach bedarf von SpielFluss in das SwitchPanel geladen (vielleicht vergleichbar mit dem von TomateSalat verlinkten CardLayout).


Mein Problem war, dass ich nicht wusste, wie ich die Events, die auf die Button im Hauptmenü ausgelöst wurden, an die Spielflussklasse weiterleiten kann.

Grüße,
Roberto
 
Zuletzt bearbeitet:

Zurück
Oben