web-dev-qa-db-fra.com

JavaFX 8 - Onglets et onglets avec FXML et contrôleurs distincts pour chaque onglet

J'espère obtenir des réponses concernant le fait d'avoir fx: inclure des instructions pour chaque onglet dans un onglet. J'ai réussi à faire en sorte que le contenu s'affiche, MAIS les méthodes de référencement de la classe de contrôleur associée me fournissent simplement une exception nullpointerreference, quelle que soit ma structure. Les contrôleurs des mises en page FXML incluses n'ont pas de méthodes constructeur ni initialisation (), sont-ils nécessaires? J'ai essayé différentes choses mais j'ai toujours la même exception.

Ce que j'ai simplement fait, c'est d'ajouter un écouteur de modification dans le volet et, lorsqu'un appui sur un onglet était enfoncé, je souhaitais renseigner des champs de texte avec certaines valeurs obtenues à partir d'une liste accessible à tous. Remarque: l'arraylist n'est pas le problème, effectuer cette opération à l'aide du contrôleur principal fonctionne bien. 

Je vais ajouter un exemple de code sous peu, mais je ne peux pas le faire maintenant. S'il vous plaît laissez-moi savoir si vous avez besoin de plus d'informations, sinon je posterai le code plus tard aujourd'hui. 

* Edit, voici mon exemple de code, tiré d’un autre thread ici sur StackOverflow . JavaFX TabPane - Un contrôleur pour chaque onglet

TestApp.Java:

public class TestApp extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        Scene scene = new Scene(new StackPane());

        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/MainTestWindow.fxml"));
        scene.setRoot(loader.load());
        MainTestController controller = loader.getController();
        controller.init();

        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

Contrôleur principal, où je veux référencer les sous-contrôleurs.

public class MainTestController {

    @FXML private TabPane tabPane;
    // Inject tab content.
    @FXML private Tab fooTabPage;
    // Inject controller
    @FXML private FooTabController fooTabPageController;

    // Inject tab content.
    @FXML private Tab barTabPage;
    // Inject controller
    @FXML private BarTabController barTabPageController;

    public void init() {
        tabPane.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Tab> observable,
                                                                        Tab oldValue, Tab newValue) -> {
            if (newValue == barTabPage) {
                System.out.println("Bar Tab page");
                barTabPageController.handleButton();
            } else if (newValue == fooTabPage) {
                System.out.println("Foo Tab page");
                fooTabPageController.handleButton();
            }
        });
    }
}

.Fxml de la vue principale

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.TabPane?>
<?import javafx.scene.control.Tab?>

<TabPane fx:id="tabPane" fx:controller="controller.MainTestController" xmlns="http://javafx.com/javafx/8.0.40"
         xmlns:fx="http://www.w3.org/2001/XInclude">
    <tabs>
        <Tab fx:id="fooTabPage" text="FooTab">
            <fx:include source="fooTabPage.fxml"/>
        </Tab>
        <Tab fx:id="barTabPage" text="BarTab">
            <fx:include source="barTabPage.fxml"/>
        </Tab>
    </tabs>
</TabPane>

FooTab:

public class FooTabController {
    @FXML private Label lblText;

    public void handleButton() {
        lblText.setText("Byebye!");
    }
}

Le fichier .fxml de FooTab:

<?xml version="1.0" encoding="UTF-8"?>

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

<?import javafx.scene.control.Button?>
<VBox xmlns:fx="http://www.w3.org/2001/XInclude" fx:controller="controller.FooTabController">
    <Label fx:id="lblText" text="Helllo"/>
    <Button fx:id="btnFooTab" onAction="#handleButton" text="Change text"/>
</VBox>

Onglet barre:

public class BarTabController {
    @FXML private Label lblText;

    public void handleButton() {
        lblText.setText("Byebye!");
    }
}

BarTab's .fxml

<?xml version="1.0" encoding="UTF-8"?>

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

<?import javafx.scene.control.Button?>
<VBox xmlns:fx="http://www.w3.org/2001/XInclude" fx:controller="controller.BarTabController">
    <Label fx:id="lblText" text="Helllo" />
    <Button fx:id="btnBarTab" onAction="#handleButton" text="Change text"/>
</VBox>

Le onAction ci-dessus pour FooTab et BarTab fonctionne avec leurs boutons respectifs. Lorsque cette méthode (handleButton) est référencée à partir du contrôleur principal, je reçois une exception.

9
Måns Thörnvik

Pour injecter un contrôleur pour un fichier FMXL inclus, vous avez besoin d'un attribut fx:id sur l'élément <fx:include>. Le contrôleur sera injecté dans un champ avec "Controller" ajouté à la valeur fx:id

Si vous souhaitez également injecter la Tab réelle, vous avez besoin d'un fx:id séparé.

Alors:

<tabs>
    <Tab fx:id="fooTab" text="FooTab">
        <fx:include fx:id="fooTabPage" source="fooTabPage.fxml"/>
    </Tab>
    <Tab fx:id="barTab" text="BarTab">
        <fx:include fx:id="barTabPage" source="barTabPage.fxml"/>
    </Tab>
</tabs>

et

@FXML private TabPane tabPane;
// Inject tab content.
@FXML private Tab fooTab;
// Inject controller
@FXML private FooTabController fooTabPageController;

// Inject tab content.
@FXML private Tab barTab;
// Inject controller
@FXML private BarTabController barTabPageController;
6
James_D

Conclusion: exemple de modèle "injecter des sous-contrôleurs"
- L'exemple ci-dessus m'a beaucoup aidé à comprendre enfin le mécanisme d'injection. Je vous remercie.
- J'ai retravaillé le code pour le rendre encore plus transparent et clair
- le code suivant est complet et fonctionne 

Tab1fooController.Java 

public class TabPaneRootController {

    @FXML private TabPane tabPane;

    //###################################Inject part#############################################
    // Inject tab content
    @FXML private Tab tab1_foo; //from TabPaneRootView.fxml: <Tab fx:id="tab1_foo" ...>
    @FXML private Tab tab2_bar; //from TabPaneRootView.fxml: <Tab fx:id="tab2_bar" ...>

    // Inject tab controller
    @FXML private Tab1fooController xxx_tab1foo_xxxController;//TabPaneRootView.fxml_include_fx:id="xxx_tab1foo_xxx" + "Controller"
    @FXML private Tab2barController xxx_tab2bar_xxxController;//TabPaneRootView.fxml_include_fx:id="xxx_tab2bar_xxx" + "Controller"
   //###########################################################################################

        public void init() {
               tabPane.getSelectionModel().selectedItemProperty().addListener((ObservableValue<? extends Tab> observable,
                                                                    Tab oldValue, Tab newValue) -> {                                                                                                    
            if (newValue == tab2_bar) {
                System.out.println("- 2.Tab bar -");
                System.out.println("xxx_tab2bar_xxxController=" + xxx_tab2bar_xxxController); //if =null => inject problem 
                xxx_tab2bar_xxxController.handleTab2ButtonBar();
            } else if (newValue == tab1_foo) {
                System.out.println("- 1.Tab foo -");
                System.out.println("xxx_tab1foo_xxxController=" + xxx_tab1foo_xxxController); //if =null => inject problem
                xxx_tab1foo_xxxController.handleTab1ButtonFoo();
            } else {
                System.out.println("- another Tab -");
            }
        });
    }
}

tabPaneRootView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Tab?
<?import javafx.scene.control.TabPane?>

<TabPane fx:id="tabPane" xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1"  fx:controller="controller.TabPaneRootController">
<tabs>
    <Tab fx:id="tab1_foo" text="myTab1foo">
        <fx:include fx:id="xxx_tab1foo_xxx" source="tab1fooView.fxml" />
    </Tab>
    <Tab fx:id="tab2_bar" text="myTab2bar">
        <fx:include fx:id="xxx_tab2bar_xxx" source="tab2barView.fxml" />
    </Tab>
</tabs>

Tab1fooController.Java

public class Tab1fooController {
    @FXML private Label tab1_label_showText;

    public void handleTab1ButtonFoo() {
        if( tab1_label_showText.getText().equals("tab1 aaa") ) {
            tab1_label_showText.setText("tab1 iii");
        } else {
            tab1_label_showText.setText("tab1 aaa");
        }
    }
}

tab1fooView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns="http://javafx.com/javafx/8.0.111" xmlns:fx="http://javafx.com/fxml/1" fx:controller="controller.Tab1fooController">
    <Label fx:id="tab1_label_showText" text="Tab1_start" />
    <Button fx:id="tab1_button_foo" onAction="#handleTab1ButtonFoo" text="tab1_button_foo" />
</VBox>

Tab2barController.Java

public class Tab2barController {
    @FXML private Label tab2_label_showText;

    public void handleTab2ButtonBar() {             
        if( tab2_label_showText.getText().equals("tab2 bbb") ) {
            tab2_label_showText.setText("tab2 jjj");
        } else {
            tab2_label_showText.setText("tab2 bbb");
        }
    }
}

tab2barView.fxml

<?xml version="1.0" encoding="UTF-8"?>

<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.layout.VBox?>

<VBox xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/8.0.111" fx:controller="controller.Tab2barController">
    <Label fx:id="tab2_label_showText" text="Tab2_start" />
    <Button fx:id="tab2_button_bar" onAction="#handleTab2ButtonBar" text="tab2_button_bar" />
</VBox>

TestApp.Java

public class TestApp extends Application {
    @Override
    public void start(Stage primaryStage) throws Exception {
        Scene scene = new Scene(new StackPane());

        FXMLLoader loader = new FXMLLoader(getClass().getResource("/view/tabPaneRootView.fxml"));
        scene.setRoot(loader.load());
        TabPaneRootController controller = loader.getController();
        controller.init();

        primaryStage.setScene(scene);
        primaryStage.setTitle("Inject TabController");
        primaryStage.show();
    }

    public static void main(String[] args) {
        launch(args);
    }
}

- Structure de l'annuaire
- Exemple démarré

0
Sten