JavaFX Menü und mehrere Scenes

Garog0201

Mitglied
Hallo,

ich möchte eigentlich etwas ganz einfaches realiseren, bzw. etwas ganz gewöhnliches.
Ich habe eine Mainmenüleiste mit Menüpunkten, diese sollte immer zu sehen sein.
Erstellt habe ich diese im fxml woraus ich in der Main Klasse dann eine Scene mache.
Nun möchte ich das bei einem Klick auf ein Menüitem eine andere Scene geladen wird.
Bzw. es muss nicht mal eine andere Scene sein, es sollten einfach andere Dinge angezeigt werden.
Mit Swing habe ich das über Components gemacht die ich dann jeweils als Layout gesetzt habe.
Nun dachte ich, kann ich meine ganzen Elemente (Buttons, Labels, etc..) ja auch in eine Group stecken und diese dann immer hinzufügen.
FX ist neu für mich und die Infos dazu im Web sind recht mager (und vor allem nur englisch)

Hier würde ich mich über ein paar Anregungen wie ich das ganze am saubersten lösen kann sehr freuen.

Vielen Dank
 

Garog0201

Mitglied
Dann werde ich mir mal selbst Infos geben :)

Ich habe es nun so das ich mehrere fxml Dateien habe, jede beschreibt eine "andere Seite" in meinem Programm.
Das gemeinsame Menü wird in jeder fxml Datei mit Hilfe von
Java:
<fx:include source="Menubar.fxml"/>
eingebunden.
Zu jeder fxml Datei habe ich mir eine css Datei angelegt (macht es übersichtlicher, kann natürlich auch alles in eine Datei)
Jede fxml Datei hat ihren eigenen Controller für die Events
Im Controller für das Hauptmenü weiße ich der Stage immer die jeweils neue Scene zu die angezeigt werden soll.
Nun mal etwas Code

Menü fxml
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.VBox?>

<VBox id="vbox" prefHeight="25" prefWidth="700" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MenuController">
    <children>
        <MenuBar fx:id="menuBar">
            <menus>
                <Menu text="Menü">
                    <items>
                    <Menu text="Projekt">
                        <items>
                            <MenuItem onAction="#handelProjektAnlegen" text="Projekt anlegen" />
                            <MenuItem onAction="#handelProjektlogbuch" text="Logbuch führen" />
                        </items>
                    </Menu>
                    <MenuItem onAction="#handelEmail" text="eMails umbennen" />
                    <SeparatorMenuItem />
                    <MenuItem onAction="#handelExit" text="Beenden" />
                    </items>
                </Menu>

                <Menu text="Einstellungen">
                <items>
                    <MenuItem onAction="#handelEmailEinstellungen"  text="eMail Adressen" />
                </items>
                </Menu>
                <Menu text="Über">
                    <items>
                        <MenuItem onAction="#handelInfo"  text="Info" />
                    </items>
                </Menu>
            </menus>
        </MenuBar>
    </children>
</VBox>

Controller dazu
Java:
public class MenuController implements Initializable
{
    @FXML
    private MenuBar menuBar;

    @Override
    public void initialize(java.net.URL arg0, ResourceBundle arg1) {

    }

    public void handelProjektAnlegen(ActionEvent actionEvent) throws IOException {
        System.out.println("Projekt anlegen anzeigen");
        Stage stage = (Stage) menuBar.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("../fxml/Menu.Projekt.anlegen.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public void handelProjektlogbuch(ActionEvent actionEvent) throws IOException {
        System.out.println("Projektlogbuch anzeigen");
        Stage stage = (Stage) menuBar.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("../fxml/Menu.Projekt.Logbuch.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public void handelEmail(ActionEvent actionEvent) throws IOException {
        System.out.println("eMail umbennen anzeigen");
        Stage stage = (Stage) menuBar.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("../fxml/Menu.EmailsUmbennen.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public void handelEmailEinstellungen(ActionEvent actionEvent) throws IOException {
        System.out.println("eMail Einstellungen anzeigen");
        Stage stage = (Stage) menuBar.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("../fxml/Einstellungen.eMail.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public void handelInfo(ActionEvent actionEvent) throws IOException {
        System.out.println("Infoseite anzeigen");
        Stage stage = (Stage) menuBar.getScene().getWindow();
        Parent root = FXMLLoader.load(getClass().getResource("../fxml/Ueber.Info.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }

    public void handelExit(ActionEvent actionEvent) {
        Platform.exit();
    }
}

Und dazu mal noch eine fxml der Projektscene
Java:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import javafx.scene.layout.Pane?>
<?import javafx.scene.layout.VBox?>

<VBox id="vbox" prefHeight="500" prefWidth="700" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.MenuProjektAnlegenController">
    <children>
        <fx:include source="Menubar.fxml"/>
        <Pane prefHeight="475.0" prefWidth="700.0" stylesheets="/styles/stylesheet.css">
            <children>
                <fx:define>
                    <ToggleGroup fx:id="myToggleGroup"/>
                </fx:define>

                <RadioButton id="rbeigenfertigung" fx:id="rbeigenfertigung" toggleGroup="$myToggleGroup" layoutX="15.0" layoutY="15.0" mnemonicParsing="false" text="Eigenfertigung" />
                <RadioButton id="rbfremdfertigung" fx:id="rbfremdfertigung" toggleGroup="$myToggleGroup" layoutX="15.0" layoutY="35.0" mnemonicParsing="false" text="Fremdfertigung" />

                <Label layoutX="15.0" layoutY="70.0" text="Projektnummer" />
                <Label layoutX="15.0" layoutY="130.0" text="Kunde" />
                <Label layoutX="15.0" layoutY="190.0" text="Beschreibung" />
                <Label layoutX="15.0" layoutY="250.0" text="Offerte" />
                <Label layoutX="15.0" layoutY="310.0" text="Ursprungsprojekt" />

                <Label id="beispiellabel" layoutX="530.0" layoutY="70.0" text="Beispiel : " />
                <Label id="beispiellabel" layoutX="530.0" layoutY="130.0" text="Beispiel : " />
                <Label id="beispiellabel" layoutX="530.0" layoutY="190.0" text="Beispiel : " />
                <Label id="beispiellabel" layoutX="530.0" layoutY="250.0" text="Beispiel : " />
                <Label id="beispiellabel" layoutX="530.0" layoutY="310.0" text="Beispiel : " />

                <TextField id="projektnummer" fx:id="projektnummer" layoutX="15.0" layoutY="90.0" prefHeight="25.0" prefWidth="670.0" />
                <TextField id="projektkunde" fx:id="projektkunde" layoutX="15.0" layoutY="150.0" prefHeight="25.0" prefWidth="670.0" />
                <TextField id="projektbeschreibung" fx:id="projektbeschreibung" layoutX="15.0" layoutY="210.0" prefHeight="25.0" prefWidth="670.0" />
                <TextField id="projektofferte" fx:id="projektofferte" layoutX="15.0" layoutY="270.0" prefHeight="25.0" prefWidth="670.0" />
                <TextField id="projektursprung" fx:id="projektursprung" layoutX="15.0" layoutY="330.0" prefHeight="25.0" prefWidth="670.0" />

                <Button id="erstelleProjekt" fx:id="erstelleProjekt" layoutX="15.0" layoutY="388.0" mnemonicParsing="false" text="Projektordner anlegen" />
            </children>
        </Pane>
    </children>
</VBox>

Damit klappt das umschalten durch das Menü wunderbar. :)

Jetzt habe ich aber ein anderes Problemchen... in meiner Main Klasse erstelle ich ein Datenmodel, wie bekomme ich das nun in die Controller Klassen hinein ??
Als Beispiel
Java:
public class Main extends Application
{
    private static Model m = new Model();

    public static void main(String[] args)
    {
        m.setVersion("1.0.0");
        launch(args);
    }


    @Override
    public void start(final Stage stage) throws Exception
    {
        stage.getIcons().add(new Image("file:src/img/a128x128.png"));
        stage.setTitle("Programmnme v" + m.getVersion());

        Parent root = FXMLLoader.load(getClass().getResource("fxml/Startseite.fxml"));
        stage.setScene(new Scene(root));
        stage.show();
    }
}
Hier setze ich die Projektversion, diese soll nun im Programmkopf auftauchen (tut sie ja) aber auch auf der Infoseite des Programms was ja eine eigene Scene ist.
Irgendwie muss ich ja jetzt dem im fxml definierten Textelement den Text aus dem Model zuweisen.
Ich dacht da im ersten Moment dran dies über das initialize des Controllers der Infoseite zu machen.
Java:
public class UeberInfoController implements Initializable {
    public Label version;

    @Override
    public void initialize(URL location, ResourceBundle resources) {
        version.setText("1.0.0");
    }
}
Wie bekomme ich dort mein Model m hin um ein
Java:
version.setText(m.getVersion)
zu realisieren ??
 

Hutzli

Aktives Mitglied
Hey, ich verstehe den Aufbau deines Programms nicht, versuche aber trotzdem mal zu helfen.
Also, die main würde ich so schreiben:

Java:
public static void main( String[] args )
{
     m.setVersion("1.0.0");
     launch(args);
}

public void start( final Stage pStage )
{
     pStage.setTitle("Whatever");
     FXMLLoader lLoader = new FXMLLoader( Main.class.getResource( "fxml/Startseite.fxml" ) );
     pStage.setScene( new Scene( lLoader.load() ) );

     // Get controller, cast it and set model
     ( (MenuController) lLoader.getController() ).setModel( m );

     // show stage
     pStage.show();
}

Zeile 14:
Damit rufst du die Instanz des im FXML File angegeben Kontrollers (MenuController) auf.
Achtung, du musst in deinem Kontroller eine Methode bereitstellen, um das Modell zu setzen.
Danach kannst du es anhand des selben Verfahrens deinem Info Fenster von dort aus weitergeben.

Noch n'kleiner Tipp: Erstelle das nächste mal ein Softwaredesign mit UML, oder sonst was. Vor allem Klassendiagramme können sehr hilfreich sein ;)
 
Zuletzt bearbeitet:

Tom299

Bekanntes Mitglied
Wenn du nur 1 Controller hast ist das so ok, ansonsten würde ich ein Interface definieren und alle Controller dieses Interface implementieren lassen. Dann kannst du jedem Controller dein Model usw. mitgeben, je nachdem, was du in deinem Interface vorgibst.
 

Hutzli

Aktives Mitglied
Ja, ein Interface wäre bei mehreren Controllern angebracht. Jedoch würde ich den String direkt im Interface erfassen und die Controller dieses benutzen lassen. Dadurch müsstest du kein Modell erstellen und dieses auch nicht übergeben.

Du könntest auch einen Ressource-Manager nach dem Singleton-Pattern implementieren und die Version in einer property Datei speichern. So hättest du eine gute Trennung. ;)
 

Garog0201

Mitglied
Hey, ich verstehe den Aufbau deines Programms nicht, versuche aber trotzdem mal zu helfen.

Zeile 14:
Damit rufst du die Instanz des im FXML File angegeben Kontrollers (MenuController) auf.
Achtung, du musst in deinem Kontroller eine Methode bereitstellen, um das Modell zu setzen.
Danach kannst du es anhand des selben Verfahrens deinem Info Fenster von dort aus weitergeben.

Noch n'kleiner Tipp: Erstelle das nächste mal ein Softwaredesign mit UML, oder sonst was. Vor allem Klassendiagramme können sehr hilfreich sein ;)

Hm, ich bin zwar absoluter frischling in dem Thema, aber wieso verstehst du das Programm nicht ?
Ich habe eine Mainklasse, die ruft mir meine Startscene auf, diese beinhaltet eine MenuBar.
Mit der MenuBar gehe ich dann in andere Scenes. Für mich eine ganz normale Anwendung ^^
Die Scenes sind mit fxml aufgebaut und werden durch die entsprechenden onActions der menuItems geladen und in die aktuelle Stage gesetzt. Ist das nicht gut ?
Vielleicht hilft das etwas mehr -> https://gist.github.com/Garog/ee979f4c50c76c554f86

Dein Tipp sieht mir recht gut aus. Ich habe bereits recht intensiv nach Lösungen gesucht. Bei stockoverflow und co. habe ich es auch versucht, da werden zum Teil Lösungsansätze geboten da steigt doch kein Vollprofi hinter wieso und warum das so geht ^^ Injections und Observer usw... machen wie ich finde das Programm auch nicht wirklich übersichtlicher und verständlicher.
Ich hatte es auch schon mit dieser Idee probiert dependency injection - Passing Parameters JavaFX FXML - Stack Overflow
Dabei habe ich allerdings das Problem, wenn ich in einer fxml eine fxml includiere, wie die MenuBar.fxml, dann bekomme ich an diese keinen Controller mehr dran.

Das befürchte ich könnte mir bei deiner Lösung auch passieren, wenn ich meine Starseite.fxml lade, kann ich deren Controller zwar mit deiner Idee mein Model übergeben, aber wie kommt das Model dann in die in der Startseite.fxml includierten Menubar.fxml an ? Schließlich lade ich hier ja die anderen Scenes auf und muss dort dann nach deiner Idee das Model wieder weitergeben. Das gleiche Problem habe ich auch mit dem Lösungsansatz in dem stackoverflow Link. Dort kann ich den Controller erstellen und über den Konstruktor mein Model mitgeben und anschließend den Controller zuweisen
[Java]
FXMLLoader loader = new FXMLLoader(getClass().getResource("fxml/Startseite.fxml"));
loader.setController(new StartseiteController(m))
Pane mainPane = loader.load();
stage.setScene(new Scene(mainPane ));
stage.show();
[/Java]
Meine Menubar.fxml hat davon allerdings nichts und müsste irgendwie an den MenubarController kommen..
Wie dem auch sei, ich werde deine Idee morgen mal ausprobieren und schauen was bei rum kommt.

Controller habe ich aktuell schon 12, passend zu den 11 Scenes und dem einen Menü.
Interfaces steht im nächsten Kapitel des Buches auf dem Tagesplan bei mir ;) Aktuell weiß ich darüber nur wie man es schreibt, mehr aber noch nicht :/

Aber danke euch beiden, ich bin sehr froh darüber überhaupt eine Antwort zu bekommen, auch wenn das für mich ordentlich neuer Lesestoff heißt :) Es gibt so wenig, vor allem deutsche, Infos zu dem Thema JavaFX, erst recht in Verbindung mit fxml und erst recht wenn man dann noch MVC dazu wirft ^^

So am Rande, ich weiß nicht wie ich es richtig formulieren soll, aber aus MVC Sicht ist die Art wie JavaFX das mit den Controller umsetzt doch genau falsch rum oder ? Als das der View den Controller aufruft und nicht der Controller den View.?
 
Zuletzt bearbeitet:

Hutzli

Aktives Mitglied
Hey, also den Aufbau habe ich nach einem zweiten Ansehen kapiert und für den Anfang ist es sicher nicht schlecht ;)
Also, wenn du jetzt unbedingt eine Klasse willst, um die Version zu speichern, dann machst du folgendes:
Erstelle ein Interface:
Java:
public interface IModelReceiver
{
     public void setModel( ModelType pModel );
}

Dies wäre das Interface (public müsstest du nicht schreiben. Methoden, welche in einem Interface deifiniert werden, sind per default public und können auch nur public sein). Nun implementierst du dieses in den Controllern, die das Modell erhalten sollen:
Java:
public class Controller implements IModelReceiver
{
     private ModelType mModel;

     @Override
     public void setModel( ModelType pModel )
     {
          this.mModel = pModel;
     }
}

Dein MenuController sollte dann in etwa so aussehen:
Java:
public class MenuController implements IModelReceiver
{
     private ModelType mModel;

     @Override
     public void setModel( ModelType pModel )
     {
          this.mModel = pModel;
     }

     public void handelInfo(ActionEvent actionEvent) throws IOException
     {
          System.out.println("Infoseite anzeigen");
          Stage stage = (Stage) menuBar.getScene().getWindow();
          FXMLLoader lLoader = new FXMLLoader( MenuController.class.getResource( "../fxml/Ueber.Info.fxml") );
          Parent root = lLoader.load();
          // Achtung: Der Info Seiten-Controller muss natürlich das
          // Interface IModelReceiver ebenso implementieren, ansonsten funktioniert
          // der nachfolgende Befehl nicht.
          ( (IModelReceiver) lLoader.getController() ).setModel( mModel );
          stage.setScene(new Scene(root));
          // Waere nicht besser: stage.showAndWait(); ?
          stage.show();
     }
}

Das ganze ist so natürlich nicht sehr schön.
Wenn ich dich wäre, würde ich, um solch generelle Informationen zu übergeben, eine Singleton Klasse implementieren, oder die Informationen direkt ins Interface schreiben:
Java:
public interface ISoftwareInformation
{
     public static final String VERSION = "1.0.0";
}
Eine Member-Deklaration in einem Interface ist per default public static final. Das müsstest du eigenlich nicht schreiben.
Dieses Interface kannst du danach in den Klassen folgendermassen verwenden:
Java:
public class Test
{
     public void writeVersion()
     {
          System.out.println( ISoftwareInformation.VERSION );
     }
}
Was natürlich am besten ist, wenn du einen ResourceManager schreibst. So kannst du Texte aus sämtlichen GUIs und Klassen in Files mit der Endung .properties verbannen.
Schau dir doch mal ResourceBundle an:
https://docs.oracle.com/javase/tutorial/i18n/resbundle/concept.html

Zu dem MVC Prinzip von JavaFX hast du nicht ganz unrecht, eigentlich sollte der Controller keine View-Element beinhalten. Der Controller sowie die View sollten lose gekoppelt werden, mir fällt aber auf die schnelle auch keine bessere Idee ein, als die jetzige Umsetzung ;)

PS.
Includiere das FXML-File wie hier beschrieben:
JavaFx Nested Controllers (FXML <include>) - Stack Overflow
Du musst nur die fx:id angeben, und kannst dann mittels @FXML die Instanz des Controllers bekommen.
FXML-File:
Code:
<fx:include fx:id="mnBar" source="MenuBar.fxml" />
MainView-Controller:
Java:
public class MainController implements IModelReceiver
{
   private Model mModel;
   
   @FXML
   private MenuBarController mnBarController;
   
   @Override
   public void setModel( Model pModel )
   {
      mModel = pModel;
      mnBarController.setModel( mModel );
   }  
}
 
Zuletzt bearbeitet:

Tom299

Bekanntes Mitglied
Ich nutze für "viewübergreifende" Daten auch immer ein Globals-Klasse, in der alle Variablen public static definiert sind. So spart man sich das Hin- und hergeschiebe zwischen den ganzen Views oder um sich einen bestimmten Status zu merken ect. oder um Stammdaten nur 1 mal Laden zu müssen.
 

Garog0201

Mitglied
Soweit erstmal danke.
Das mit dem einen String war nur noch drin als Beispiel, das Model enthält wesentlich mehr Daten, wesentlich...
Daher möchte ich schon bei dem Model bleiben.

Ich werde aber mal die beiden letzten Ansätze testen, heute Abend mehr dazu :)

@Tom999
das ist natürlich auch eine Idee mit der ich mein Problem ganz schnell lösen kann, allerdings wiederspricht das etwas dem Prinzip der Datenkapslung. Es ist einfacher, keine Frage, aber eher "unsauber" wie ich finde.

Zum Thema Interfaces habe ich mal die Insel befragt, nunja, was soll ich sagen, ist ja irgendwie nichts anderes wie eine "Vorlage" das man bestimmte Methoden in der jeweiligen Klasse welche das Interface beinhaltet erstellen muss.
Mal abgesehen von den finals oder den static Neuerungen in Java8
Oder sehe ich das falsch ?
 

Hutzli

Aktives Mitglied
Ja, kann schon sein, dass du mehr Daten im Modell hast. Es gibt jedoch Informationen, die zentral gespeichert sein sollten, um somit von jeder Klasse gebraucht werden zu können. Wie eben zum Beispiel die Version.

Zu den Interfaces hast du recht, es ist eine Implementationsvorgabe, aber noch viel mehr. So kannst du zum Beispiel eine Liste mit Interfaces vom Typ IListenerInterface anlegen (List<IListenerInterface>). Instanzen von Klassen, die dieses Interface implementieren, können so alle in dieser Liste gespeichert werden. Man kann es ein wenig als eine Erweiterung der Vererbung in Java ansehen, da Java nur die Einfachvererbung erlaubt, im Gegensatz zu C++.
Einfachvererbung gibts, da man damals, als die Sprache designt worden ist, mehreren Problemen, die Mehrfachvererbung mit sich bringt (Diamantproblem), aus dem Weg gehen und eine einfach zu verwendende Sprache erstellen wollte. Da aber nur mit Einfachvererbung kein vernünftiges Programm geschrieben werden kann, sind dann die Interfaces als Ersatz eingeführt worden, die aber auch nach einem anderen Prinzip aufgebaut sind als Klassen.
Ein Interface definiert Schnittstellen, die Klassen zur Verfügung stellen müssen.
 

Garog0201

Mitglied
.......
Ein Interface definiert Schnittstellen, die Klassen zur Verfügung stellen müssen.
gut, genau so habe ich es im ersten Moment verstanden :)
Ich hatte deinen Vorschlag ausprobiert und bin dabei auf einen ganz anderen Weg gekommen.
Die ganze Zeit habe ich das Thema mit dem includen der fxml im Kopf gehabt um auf jeder Seite das Menü zu haben.
Ich bin gerade dabei das komplett um zu designen.
So kann ich dann mit deiner getController Idee das Model perfekt durchreichen und zusätzlich setze ich auch noch von einem MainController aus den View und den Controller separat.
Sobald ich etwas Ordnung in meinem Testcode geschaffen habe, werde ich das ganze als gist bei Github schieben und präsentieren.
Habe, um damit zu mal etwas zu arbeiten, sogar ein Interface für einige Konstanten implementiert ;)
Auch wenn die getController Sache nicht das optimalste ist, ist es das was ich aktuell gut verstehe und kenne.
Das mit den Interfaces muss ich dann bei Zeiten noch mal mit einem kleinen Testprojekt ausprobieren. Hier hatte ich den Teil in der Insel auch nur fix überflogen, um überhaupt zu wissen was Interfaces darstellen.
Heute Abend wird es aber mit dem gist nix mehr, Projekt wird erst morgen aufgeräumt.

in diesem Sinne vielen Dank und einen schönen Abend :)

PS: es tut sehr gut mal Fragen zu stellen oder Vermuten mitzuteilen, auf deutsch, und diese dann so Gut beantwortet zu bekommen !
 

Hutzli

Aktives Mitglied
hehe, okay bin aufs Ergebnis gespannt ;)

Und ja, gebe mir Mühe die Fragen möglichst klar und ausführlich zu beantworten, vielen Dank dir und einen schönen Abend ^^
 

Garog0201

Mitglied
Gut das ich es gestern Abend nicht mehr auf Gist gestellt habe.
Mir kamen über Nacht noch ein paar Ideen mit denen ich das getController ebenfalls komplett beseitigen konnte.

Damit sollte ich jetzt ziemlich gut an einem MVC Pattern liegen und lade auch keine Controller aus den fxml.

Der springende Punkt war das ich "gelernt" habe, das ich ein Hauptfenster mit einer fxml anlegen kann mit z.B. einer Pane ohne Inhalt in Vorbereitung, in diese ich dann meine beliebigen Fensterinhalte (mit fxml erstellt) laden kann.
Jedes "Programmfenster verfügt nun auch über seinen eigenen Controller der zugewiesen wird.
Das durchreichen des Models ist jetzt auch optimal über die Konstruktoren gelöst.

Und ein Interface dient mal als Test, da kommt dann später der Rest an Programmfenstern noch rein :)

Damit bin ich jetzt zufrieden :)

Vielen Dank für die gute Unterstützung

Hier das Ergebnis einer auf das wesentliche gekürzten Version
https://gist.github.com/Garog/59f45f4b1e7acb642c1c
 
Zuletzt bearbeitet:

Ruzmanz

Top Contributor
Das ist vom Prinzip her nicht verkehrt. Halte es aber für unnötig. Du wirst jedes größere Projekt nach diesem Muster bauen und noch "Optimierungspotential" finden. Deshalb solltest du gleich auf ein Application Framework setzen. Ich nutze gerne DataFX, wobei ich dort auch erst vor kurzem eingestiegen bin.

DataFX bietet die Flow-API. Du erstellst lediglich die Klasse MainController und annotierst sie mit @FXMLController. Dort kannst du den Pfad zur FXML mitgeben.
Java:
@FXMLController("fxml/main.fxml")
public class MainController {}
Mit zwei Befehlen lädst du deine FXML automatisch in die Stage.
Java:
@Override
public void start(Stage stage) throws FlowException {
	new Flow(MainController.class).startInStage(stage);
}
Nun möchtest du einen "Inner-Flow", d.h. das Menü bleibt erhalten und lediglich der Inhalt wird ersetzt. Hierfür Annotieren wir den MenuProjektAnlegenController wieder mit @FXMLController.
Java:
@FXMLController("fxml/Menu.Projekt.anlegen.fxml")
public class MenuProjektAnlegenController {}
Zudem definieren wir den "Inner-Flow" im PostConstruct.
Java:
public class MainController {
	@FXML private Pane programmInhalt;

	@PostConstruct
	public void init() throws FlowException {
		programmInhalt.getChildren().add(new Flow(MenuProjektAnlegenController.class).createHandler().start());
	}
}
Die Flow-API bietet nicht nur die Möglichkeit eine FXML zu laden, sondern auch zwischen einzelnen Controllern zu navigieren. Letztendlich würde der MainController folgendermaßen aussehen:
Java:
@FXMLController("fxml/main.fxml")
public class MainController {
	@FXML private Pane programmInhalt;

	private FlowHandler innerFlow;

	@PostConstruct
	public void init() throws FlowException {
		innerFlow = new Flow(MenuProjektAnlegenController.class).createHandler();
		programmInhalt.getChildren().add(innerFlow.start());
	}

	@FXML
	private void anlegenProjekt(ActionEvent actionEvent) throws Exception {
		innerFlow.navigateTo(MenuProjektAnlegenController.class);
	}

	@FXML
	private void anlegenService(ActionEvent actionEvent) throws Exception {
		innerFlow.navigateTo(MenuServiceAnlegenController.class);
	}

	@FXML
	private void beendeProgramm(ActionEvent actionEvent) {
		Platform.exit();
	}
}
Unschwer zu erkennen ist, dass ich Model rausgeworfen habe. Anstatt eine Model-Instanz zu erzeugen, wird die Klasse Model mit @ApplicationScoped annotiert.
Java:
@ApplicationScoped	
public class Model {
}
Dadurch können wir in der gesamten Applikation mit "@Inject" auf diese Instanz zugreifen. Eine manuelle Verwaltung entfällt.
Java:
@FXMLController("fxml/Menu.Service.anlegen.fxml")
public class MenuServiceAnlegenController {
	@Inject private Model m;

	@FXML
	public void erstelleService(ActionEvent actionEvent) {
		System.out.println(m.getTestwert());
	}
}

Gesamt: https://gist.github.com/RuZman/0e20597a67daff8aba25 (Stylesheets etc. und ungenutzten Code habe ich rausgeworfen)

Quellen:
DataFX Controller Framework Preview - GuiGarage
DataFX 8.0 Tutorials
 
Zuletzt bearbeitet:

Hutzli

Aktives Mitglied
Sieht ja schön und gut aus, würde ihm für den Anfang aber empfehlen, nicht auf solche Frameworks zu setzen. Er sollte erst mal lernen, selbst ein Design aufzubauen. Danach kann man sich immer noch mit Frameworks befassen, und man kann die Funktionsweise sicher besser nachvollziehen.
 

Garog0201

Mitglied
Danke Ruzmanz für die schöne und ausführliche Antwort, ich werde sie mir mal als pdf bei Seite legen.
Aber aktuell trifft Hutzli den Nagel auf den Kopf. Ich hatte auch erst Frameworks angeschaut, aber da bedarf es so viel Wissen nur um das Framework selbst, das dies völlig an meinem Ziel vorbei ging. Das ist wie C++ lernen "oder" qt ^^
So wie ich es jetzt gemacht habe verstehe ich auch was ich gemacht habe und bleibe erstmal "bei den Basics", das hat auch den Vorteil das ich einfach etwas ändern kann und mich nicht auf die Funktionen eines Frameworks verlassen muss.
 

dzim

Top Contributor
@Ruzmanz: Danke für dieses Bsp.!
Ich hatte mal ein etwas grösseres Projekt auf die "klassische" Art erstellt (wobei ich die Inter-View-Kommunikation mit einem Event-Dispatcher gemacht habe und nicht mit einem zentralen ViewModel - ob das gut oder schlecht ist, darüber lässt sich streiten, aber es funtkionierte :) ). Bei mir auf der Agenda steht für das nächste Projekt def. DataFX und dein Bsp. ist fast schon als Tutorial zu werten! danke also dafür!
 
Ähnliche Java Themen
  Titel Forum Antworten Datum
L JavaFX Mehrere JavaFX Szenen mit einem Menü AWT, Swing, JavaFX & SWT 1
J GUI Programmierung Popup-Menü AWT, Swing, JavaFX & SWT 4
J Java GUI Dropdown-Menü anzeigen AWT, Swing, JavaFX & SWT 5
I Von Menü: Seite zu Seite springen (CardLayout) AWT, Swing, JavaFX & SWT 8
B Swing Menü geht nicht AWT, Swing, JavaFX & SWT 5
AmsananKING Java Menü-Problem AWT, Swing, JavaFX & SWT 1
M Eine Datei auf den Apache Server hochladen - über das Menü im JavaProgramm AWT, Swing, JavaFX & SWT 7
H Swing Auf Klick auf Menü-Eintrag reagieren AWT, Swing, JavaFX & SWT 0
C JavaFX Inhalt eines SplitPane's durch Menü-Auswahl ändern? AWT, Swing, JavaFX & SWT 13
M Menü ohne Menübar umsetzen[SWT] AWT, Swing, JavaFX & SWT 8
RalleYTN Swing Menü für Texteditor (Rechtsklick) AWT, Swing, JavaFX & SWT 4
D javafx.scene.control.TreeView als dropdown Menü AWT, Swing, JavaFX & SWT 6
J Swing aufklappbares Menü AWT, Swing, JavaFX & SWT 0
K JavaFX Fenster aufrufen über Menü AWT, Swing, JavaFX & SWT 1
F Swing Ein 2D-Game Menü mit framefüllenden Button AWT, Swing, JavaFX & SWT 6
J 2D-Grafik Menü programmieren AWT, Swing, JavaFX & SWT 2
X Popup Menü nur bei besonderem Fall öffnen AWT, Swing, JavaFX & SWT 3
U Größe eines Button im Menü ändern AWT, Swing, JavaFX & SWT 1
M Menü mit Buttons AWT, Swing, JavaFX & SWT 8
J Graphisches Game Menü AWT, Swing, JavaFX & SWT 9
J Maus "locken" für Menü AWT, Swing, JavaFX & SWT 8
S SWT: Drop-Down Menü-Einträge mit Tooltip hervorheben AWT, Swing, JavaFX & SWT 3
H Swing Menü mit Bildern AWT, Swing, JavaFX & SWT 2
C Swing Wie kann ich im Programm das Menü schließen AWT, Swing, JavaFX & SWT 2
D Jtable mit Dropdown Menü erweitern funktioniert nicht AWT, Swing, JavaFX & SWT 5
M Swing In GUI-Builder-JFrame mit Menü Schreiben und Zeichnen AWT, Swing, JavaFX & SWT 4
J Menü umstrukutierem AWT, Swing, JavaFX & SWT 5
P versch. JPanel Klassen über Menü öffnen AWT, Swing, JavaFX & SWT 12
R Bitte kein Menü bei F10 AWT, Swing, JavaFX & SWT 9
A Swing Fenstergröße mittels Menü verändern AWT, Swing, JavaFX & SWT 3
kodela Tastaturereignisse für Menü- und Anwenderbereich AWT, Swing, JavaFX & SWT 14
TheWhiteShadow Swing Problem mit Icon-Menü-Leiste AWT, Swing, JavaFX & SWT 5
E Windows Kontext Menü - Laufendes Programm AWT, Swing, JavaFX & SWT 3
G Menü verschwindet durch .setText() AWT, Swing, JavaFX & SWT 4
J Swing Natives Menü unter OS X erstellen ? AWT, Swing, JavaFX & SWT 8
J Menü beschriftung wird nicht verändert AWT, Swing, JavaFX & SWT 7
J LookAndFeel Titelbar & About Menü AWT, Swing, JavaFX & SWT 6
Eldorado Swing Popup-Menü mit Jspinner AWT, Swing, JavaFX & SWT 4
Semox Swing Shortcuts in Menü realisieren AWT, Swing, JavaFX & SWT 2
R Swing Menü wird nicht angezeigt AWT, Swing, JavaFX & SWT 2
Semox Swing Menü und JPanel AWT, Swing, JavaFX & SWT 6
S Menü Item "abhaken" lassen vom Benutzer AWT, Swing, JavaFX & SWT 2
G Swing Fortschrittsbalken im Fenster: Menü deaktivieren / abfangen? AWT, Swing, JavaFX & SWT 27
L Verzeichnis Menü (Durchsuchen) AWT, Swing, JavaFX & SWT 2
R JRadioButtonGroup - im Menü und im losgelösten Fenster AWT, Swing, JavaFX & SWT 3
J JButton und Menü AWT, Swing, JavaFX & SWT 5
S Dropdown-Menü wie auf der Eclipse-Toolbar AWT, Swing, JavaFX & SWT 7
T einfaches Menü in swing das nicht herunterklappt? AWT, Swing, JavaFX & SWT 4
M Menü mit Layout AWT, Swing, JavaFX & SWT 10
N Fenster mit Menü AWT, Swing, JavaFX & SWT 5
V Menüeinträge im DropDown-Menü deaktivieren AWT, Swing, JavaFX & SWT 3
B Applet Menü AWT, Swing, JavaFX & SWT 6
B Dropdown-Menü im Explorer AWT, Swing, JavaFX & SWT 4
E Anfänger-JPanel aus Menü aufrufen AWT, Swing, JavaFX & SWT 4
T Scrollbalken für ein Menü oder laufendes Dropdown-Menü wie? AWT, Swing, JavaFX & SWT 34
G Funktion für PopUp Menü AWT, Swing, JavaFX & SWT 32
ElViZ JCheckBoxMenuItem Problem - Menü soll offen bleiben. AWT, Swing, JavaFX & SWT 3
S Menü AWT, Swing, JavaFX & SWT 31
L F10 Taste öffnet das Menü AWT, Swing, JavaFX & SWT 7
M Combobox verdeckt Menü AWT, Swing, JavaFX & SWT 2
T Windows-Typisches Menü für Swing AWT, Swing, JavaFX & SWT 3
D Chinesisches Menü AWT, Swing, JavaFX & SWT 6
D Pulldown Menü erstellen; welche Klasse? AWT, Swing, JavaFX & SWT 2
T Tray-Icon-Menü unter Linux AWT, Swing, JavaFX & SWT 10
J Context Menü Maus AWT, Swing, JavaFX & SWT 3
welterde Menü in der Titelleiste des JInternalFrame AWT, Swing, JavaFX & SWT 4
T Popup-Menü unter Linux AWT, Swing, JavaFX & SWT 2
G Swing Menü Hauptfenster AWT, Swing, JavaFX & SWT 14
K Menü mit ALT-D öffnen AWT, Swing, JavaFX & SWT 13
M Ereignis: Menü offen? AWT, Swing, JavaFX & SWT 2
J Icons mit Text als Menü AWT, Swing, JavaFX & SWT 2
G Problem mit Kontextmenu(Popup Menü) AWT, Swing, JavaFX & SWT 3
G Menü hervorheben, wenn Item ausgewählt ist? AWT, Swing, JavaFX & SWT 2
B Menü-Bedienung mit Keys unter AWT! AWT, Swing, JavaFX & SWT 3
J Drop-down menü in Toolbar Button AWT, Swing, JavaFX & SWT 8
G Rechte Maustaste soll Menü aufrufen AWT, Swing, JavaFX & SWT 11
G Problem mit Menü/Button auf Hintergrundbild AWT, Swing, JavaFX & SWT 10
G Datei per Menü laden und und in JTextArea darstellen AWT, Swing, JavaFX & SWT 4
A Fenster über Menü schließen AWT, Swing, JavaFX & SWT 2
G Menü oder Layout? AWT, Swing, JavaFX & SWT 2
P Menü soll sich nur nach links aufbauen... AWT, Swing, JavaFX & SWT 7
I Swing: Menü verschwindet beim Einfügen eines Bildes AWT, Swing, JavaFX & SWT 15
J JTextField immer über Menü der JComboBox gezeichnet AWT, Swing, JavaFX & SWT 2
G menü AWT, Swing, JavaFX & SWT 9
C ActionListener für dynamisches Menü AWT, Swing, JavaFX & SWT 8
G Wie kann man ein Kontext-Menü erstellen? AWT, Swing, JavaFX & SWT 2
T Swing Mehrere Ausgaben in JTextArea AWT, Swing, JavaFX & SWT 2
H Mehrere Panels auf JFrame AWT, Swing, JavaFX & SWT 8
S Mehrere Tabellen Zellen gleichzeitig färben AWT, Swing, JavaFX & SWT 5
Apfelbaum2005 Swing JFrame mehrere JPanels mit unterschiedlichen Formen hinzufügen AWT, Swing, JavaFX & SWT 1
K JavaFX unterschiedliche (mehrere Fenster) in seperater Main Methode AWT, Swing, JavaFX & SWT 26
I Scene Builder - mehrere Seiten AWT, Swing, JavaFX & SWT 6
P Swing Mehrere JLabels mit ImageIcon in JPanel lesen AWT, Swing, JavaFX & SWT 1
schoel27 Mehrere JButtons sollen das gleiche Event auslösen AWT, Swing, JavaFX & SWT 2
Z GUI Forms - Mehrere Fenster in einem Projekt AWT, Swing, JavaFX & SWT 18
M mehrere jTextField untereinander AWT, Swing, JavaFX & SWT 1
N Bilder auf Button einfügen und mehrmals ändern (ein Button, mehrere ActionListener) AWT, Swing, JavaFX & SWT 2
B Swing Sudoku: Laden / Speichern von Zahlen aus/in mehrere JTextFields aus/in eine(r) Textdatei AWT, Swing, JavaFX & SWT 9
M JavaFX JavaFX in mehrere Controller AWT, Swing, JavaFX & SWT 21
R mehrere buttons mit forschleife kreieren und individuell bearbeiten AWT, Swing, JavaFX & SWT 1

Ähnliche Java Themen

Neue Themen


Oben