JavaFX Gleiche Controller-Instanz für inludiertes FXML

Bitte aktiviere JavaScript!
Hallo zusammen,

entweder ich stehe auf dem Schlauch oder es ist tatsächlich eine komplexere Sache in JavaFX:
Ich verwende JavaFX (8) mit FXML und möchte in einer - bereits großen - FXML-Datei eine andere inkludieren - hauptsächlich um die Datei nicht größer werden zu lassen.
Beide sollen aber die gleiche Controller-Instanz verwenden.

Hier ein Beispiel dass es verdeutlichen soll:
Java:
public class DerController {
  ...

  @FXML
  public void buttonImHauptFXMLgeklickt() {
  ... ich werde gefunden
  }

  @FXML
  public void buttonImSubFXMLgeklickt() {
  ... mich findet es nicht
  }
}
Die Haupt-FXML-Datei welche den Controller hat:
Code:
<VBox ...>
  <!-- viele UI-Komponenten -->
  <Button text="Haupt fxml" onAction="#buttonImHauptFXMLgeklickt" />

  <HBox>
  <fx:include source="subFxml.fxml" />
  </HBox>
</VBox>
Die Sub-FXML-Datei welche inkludiert wird:
Code:
<GridPane ....>
  <!-- diverse UI-Kompenten -->
  <Button text="Sub fxml" onAction="#buttonImSubFXMLgeklickt" />
</GridPane>
Geladen wird die Haupt-FXML-Komponenten über FXMLLoader wo ich die Controller-Instanz auch direkt setze. Das heißt der Controller wird nicht vom FXML instanziiert.
Für die inkludierte FXML-Datei möchte ich nun auch gerne die gleiche Controller-Instanz verwenden.

Starte ich das Ganze jedoch nach dem obigen Schema, bekomme ich folgenden Fehler:
Code:
Caused by: javafx.fxml.LoadException: No controller specified.
Die Stelle ist auch eindeutig: Dort wo im Sub-FXML die onAction-Deklaration ist hat er keinen Controller.

Kennt jemand eine Lösung oder hat sonstige Meinungen dazu? Ich kenne schon ein paar Workarounds, die arbeiten aber alle ohne ein fx:inlcude sondern laden das Sub-FXML separat und bauen die UI dann im Code zusammen.


Vielen Dank im Voraus!
 
A

Anzeige




Vielleicht hilft dir unser Java-Tutorial hier weiter —> (hier klicken)
Hi,
Ja, du kannst in ein include den selben Controller wie die "Hauptview" verwenden. Siehe nachfolgend ein Beispiel mit 3 FXMLs und 1.Controller.
ChildView1.fxml und ChildView2.fxml sind im MainView.fxml included. Alle 3 FXMLs benutzen den MainViewController.
MainView.fxml:
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.VBox?>

<AnchorPane prefHeight="280.0" prefWidth="500.0"
    xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2"
    fx:controller="test11.MainViewController">
    <children>
        <VBox prefHeight="280.0" prefWidth="500.0"
            AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0"
            AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="0.0">
            <children>
                <fx:include fx:id="child1" source="ChildView1.fxml" />
                <fx:include fx:id="child2" source="ChildView2.fxml" />
            </children>
        </VBox>
    </children>
</AnchorPane>
MainViewController.java:
Java:
package test11;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.control.Button;
import javafx.scene.layout.AnchorPane;

public class MainViewController {
    @FXML
    private Parent view;
    @FXML
    private AnchorPane child1;
    @FXML
    private AnchorPane child2;

    @FXML
    private Button button1;
    @FXML
    private Button button2;
    @FXML
    private Button button3;
    @FXML
    private Button button4;
    
    @FXML
    protected void handleButtonEvent(ActionEvent event) {
        String parentName = ((Node) event.getSource()).getParent().getParent().getId();
        System.out.println("ChildViewController: " + ((Button)event.getSource()).getText() + " von " + parentName + " wurde gedrückt...");
    }

    @FXML
    void initialize() {
        System.out.println("MainViewController.initialize()");
    }
}
ChildView1.fxml:
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>

<AnchorPane fx:id="child1" id="child1" prefHeight="244.0" prefWidth="568.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="test11.MainViewController">
    <children>
        <HBox id="hBox1" layoutX="32.0" layoutY="14.0" prefHeight="51.0" prefWidth="200.0" spacing="10.0">
            <children>
                <Button fx:id="button1" prefHeight="37.0" text="Button 1" onAction="#handleButtonEvent" />
                <Button fx:id="button2" prefHeight="37.0" text="Button 2" onAction="#handleButtonEvent" />
            </children>
        </HBox>
    </children>
</AnchorPane>
ChildView2.fxml:
Code:
<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.*?>
<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.scene.layout.AnchorPane?>
<?import javafx.scene.layout.HBox?>
<?import javafx.scene.control.Button?>

<AnchorPane fx:id="child2" id="child2" prefHeight="244.0" prefWidth="568.0" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="test11.MainViewController">
    <children>
        <HBox id="hBox2" layoutX="32.0" layoutY="14.0" prefHeight="51.0" prefWidth="200.0" spacing="10.0">
            <children>
                <Button fx:id="button3" prefHeight="37.0" text="Button 3" onAction="#handleButtonEvent" />
                <Button fx:id="button4" prefHeight="37.0" text="Button 4" onAction="#handleButtonEvent" />
            </children>
        </HBox>
    </children>
</AnchorPane>
Main.java:
Java:
package test11;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.stage.Stage;

public class Main extends Application {

    public void start(Stage primaryStage) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("MainView.fxml"));
            Parent rootElement = (Parent) loader.load();
            Scene scene = new Scene(rootElement, 800, 600);
            primaryStage.setTitle("JavaFX");
            primaryStage.setScene(scene);
            primaryStage.show();
        }
        catch (Exception e)
        {
            e.printStackTrace();
        }
    }

    public static void main(String[] args) {    
        launch(args);
    }
}
Vielleicht wäre es aber besser, für jedes fxml einen separaten Controller zu erstellen, damit es übersichtlicher strukturiert werden kann... (ist nur so meine Meinung... ;-) )
 
Zuletzt bearbeitet:
Passende Stellenanzeigen aus deiner Region:

Neue Themen

Oben