Mehrere Actions

Ich habe eine fxml die ala oberste Komponente ein BorderPane hat. Im obersten Bereich (Top) befindet sich meine Menubar. Dazu habe ich auch einen Controller. Jetzt haette ich gerne noch ne Toolbar die die wichtigsten Actions als Buttons hat. Die befindet sich auch in ner fxml, aber auch mit anderen Komponenten. Diese fxml besitzt einen anderen Controller mit sen Handler Methoden fuer eben diese anderen Komponenten. Meine Frage nun: wie schaffe ich es die Actions der Menubar zu nutzen ohne alles in den zweiten Controller schreiben zu muessen?

Leider garnicht. Angeregt durch die FXML-Einführung habe ich mal etwas mit “nested controllers” und den Möglichkeiten des Binding in fxml herumgespielt. Du kannst Dir den “Subcontroller” problemlos an deinen Hauptcontroller durchreichen. Aber das Binding funktioniert in fxml (gibts auch ein kurzes Beispiel in dem Artikel) immer nur auf einer Ebene, man kann keine Elemente der einen fxml-Datei an Elemente einer anderen binden. Vielleicht bin ich aber auch nur zu dämlich und Jemand hier kennt doch noch einen Weg.

Naja du könntest dir den EventBus zur Hilfe nehmen. Und über diesen einen Event auslösen beim Tastendruck.

Ich habe mich dahingehend auch informiert und bin wie hobelhai der Meinung das dies so nicht möglich ist.

Ich habe es bei mir so gelöst das ich mir einen “HauptController” gemacht habe, und diesen meinen SubControllern übergebe. Die Sachen die ich danach mehrmals gebraucht habe, übergebe ich dem hauptController.

Hatte die Tage auch mal mit JavaFX rumgespielt und das ganze so gelöst:

Mein GUI hat einen Maincontroller. Einzelne Bereiche werden dann in einzelne Komponenten unterteil, mit eigenem Controller. Diese controller lasse ich mir in meinen Hauptcontroller injecten mit: @FXML private {ControllerKlasse} {id-in-fxml}Controller;

Diesen Controllern gebe ich dann einen globalen Eventbus mit. Da jeder Controller diesen Eventbus bekommt, können diese sich an globale Events einfach ranhängen. Der Controller bearbeitet also nur noch das GUI-Event und übergibt dann ein konkretes Event an den EventBus.

@Tomate_Salat
Wie laesst man sich denn diese injecten? Irgendwie steh ich gerade aufn Schlauch
@headnut
Jetzt verstehe ich auch dein Problem in deinem letzteb Thread und warum du den EventBus genommen hast ^^

Mir ist bei meinen recherchen noch aufgefallen dass es auch eine AbstractAction Klasse gibt (oder Action interface). Man kann also fuer jede Action eine Klasse erstellen (wie bwi Swing) nur scheint es keine Moeglichkeit zu geben diese in fxml einzubinden

Das meinte ich mit „durchreichen“. So handhabe ich das auch.
Wünschenswert wäre allerdings folgendes:
Hauptfenster
[XML]<fx:root xmlns:fx=„http://javafx.com/fxml“ type=„BorderPane“ fx:controller=„example.MainPaneController“>










<fx:include source=„MyToolBar.fxml“/>

</fx:root>[/XML]
Subfenster
[XML]<fx:root xmlns:fx=„http://javafx.com/fxml“ type=„StackPane“ fx:controller=„example.MyToolBarController“>





</fx:root>[/XML]
Und das funktioniert leider so nicht. Allerdings wird an dem FXML/Binding-Kram noch eifrig weitergestrickt und da ist hoffentlich in kommenden JavaFX-Versionen mehr zu erwarten.
@groggy :
Du machst das entweder so, wie von Tomate_Salat vorgeschlagen, dann musst Du Dich aber auch streng an die von ihm angegebene Syntax halten. Wichtig! Der FXML-Parser nimmt die von Dir an die Subklasse vergebene fx:id und hängt „Controller“ hinten dran.~~ Oder Du baust Dir deine Toolbar noch in die Haupt-Datei, dann funktioniert nämlich das Binding auch einwandfrei.~~
Edit: Ist natürlich Mumpitz, dann kann man auch direkt die dafür vorgesehene Methode der Hauptklasse verwenden.

Hat ja Hobelhai mitlerweile näher ausgeführt. JavaFX gibt den Namen vor (bestehend aus der ID in der fxml + Controller) und injecten dir diesen. Alternativ könntest du dir auch eine ControllerFactory bauen, welche notwendig wird, sobald du richtiges DI (z.B. Guice) einsetzen möchtest:

loader.setControllerFactory(new Callback<Class<?>, Object>() {
    @Override
    public Object call(Class<?> aClass) {
        return guice.getInstance(aClass);
    }
});

Wenn du noch kein DI-FW einsetzen möchtest, könntest du dir auch soetwas bauen:

loader.setControllerFactory(new Callback<Class<?>, Object>() {
    @Override
    public Object call(Class<?> aClass) {
        try {
            Object controller = aClass.newInstance();
            if(controller instanceof HandleGlobalEvents) {
                ((HandleGlobalEvents) controller).register(eventBus);
            }

            return controller;
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        return null;
    }
});

....

public interface HandleGlobalEvents {
    void register(EventBus eventBus);
}

[quote=Tomate_Salat;81426]Wenn du noch kein DI-FW einsetzen möchtest, könntest du dir auch soetwas bauen:

Java Code:
final EventBus eventBus = new EventBus();
loader.setControllerFactory(new Callback<Class<?>, Object>() {

    • @Override
    • public Object call(Class<?> aClass) {
        • try {
            • Object controller = aClass.newInstance();
            • if(controller instanceof HandleGlobalEvents) {
                • ((HandleGlobalEvents) controller).register(eventBus);
            • }
            • return controller;
        • } catch (InstantiationException e) {
            • e.printStackTrace();
        • } catch (IllegalAccessException e) {
            • e.printStackTrace();
        • }
        • return null;
    • }
      });[/quote]

Und da übergibst du mit dem Eventbus einfach das Controller Objekt seh ich das richtig?

Nein, der Controller bekommt einen globalen Eventbus. Dieser kann sich dann an diesem registrieren und/oder globale Events feuern.

Sorry, mit DIESEM Satz komm ich jetzt nicht klar.
Der Controller bekommt einen globalen Eventbus. Dieser (der Eventbus ?) kann sich dann an diesem (Eventbus ?) registrieren… aeh, echt ? :suspect:
Aber vielleicht auch egal, ich muss ja nicht alles verstehen.

(“Dieser” bezog sich auf Controller) aber vllt erklär ichs doch nochmal etwas ausführlicher:

Dem FXMLLoader kann man eine ControllerFactory mitgeben. Dort erstellst du dann selber das entsprechende Controller-Objekt. In meinem Beispiel erstelle ich den Controller und wenn er das Interface HandleGlobalEvents implementiert übergebe ich einen globalen EventBus (dessen Objekt ich zuvor außerhalb der Factory erstellt habe). Ich hoffe jz wurde es ein wenig klarer