JavaFX: Как да променя динамично контролера в същия fxml файл?

Експерти! Просто искам да използвам бутон за няколко контролера, така че да направя кода си кратък. В долната част на панела с граници направих бутони за промяна на изгледа на центъра на панела с граници и след като щракна следващия бутон, той промени друг изглед, който се намира в центъра на панела с граници. Въпреки това, ако щракна върху бутона за отметка, очаквах, че ще се появи съобщението за displayMassageLabel, но то прави грешка.. Има ли някой, който да реши този проблем..? Ето примерни кодове, които просто направих по-долу.

ChangeControllerTestMain.java

package javafxapplication2;

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

/**
 *
 * @author James
 */
public class ChangeControllerTestMain extends Application {

    @Override
    public void start(Stage stage) throws Exception {
        Parent root = FXMLLoader.load(getClass().getResource("Main.fxml"));

        Scene scene = new Scene(root);

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

    /**
     * @param args the command line arguments
     */
    public static void main(String[] args) {
        launch(args);
    }

}

Main.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<BorderPane fx:id="borderPane" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication2.MainController">
   <bottom>
      <HBox alignment="CENTER" prefHeight="39.0" prefWidth="600.0" spacing="100.0" BorderPane.alignment="CENTER">
         <children>
            <Button fx:id="backButton" mnemonicParsing="false" onAction="#handleBackButtonAction" text="&lt;Back" />
            <Button fx:id="checkButton" mnemonicParsing="false" onAction="#handleCheckButtonAction" text="Check" />
            <Button fx:id="nextButton" mnemonicParsing="false" onAction="#handleNextButtonAction" text="Next&gt;" />
         </children></HBox>
   </bottom>
</BorderPane>

MainColtroller.java

package javafxapplication2;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.AnchorPane;
import javafx.scene.layout.BorderPane;

/**
 *
 * @author James
 */
public class MainController implements Initializable {

    @FXML
    private BorderPane borderPane;
    private AnchorPane anchorPane;
    private Label displayMassageLabel;

    @FXML
    private Button backButton;
    @FXML
    private Button checkButton;
    @FXML
    private Button nextButton;

    private int currentMenuNum;
    private String currentViewerPath;
    private String pathList[] = {"StartDisplay.fxml", "Menu1Display.fxml", "Menu2Display.fxml", "Menu3Display.fxml"};

    private Menu1DisplayController menu1DisplayController = new Menu1DisplayController();
    private Menu2DisplayController menu2DisplayController = new Menu2DisplayController();
    private Menu3DisplayController menu3DisplayController = new Menu3DisplayController();

    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
        currentMenuNum = 0;
        currentViewerPath = pathList[currentMenuNum];
        System.out.println(currentViewerPath);
        setControlItems(currentViewerPath, currentMenuNum);
    }

    private void setControlItems(String path, int currentMenuNum) {
        //Display setting for menu
        FXMLLoader fxmlLoader = new FXMLLoader();
        try {
            fxmlLoader.setLocation(getClass().getResource(path));
            anchorPane = fxmlLoader.load();
            //connectionViewerController = (ConnectionViewerController) fxmlLoader.getController();
        } catch (Exception e) {
            System.out.println(e.getStackTrace().toString());
            System.out.println(e.getMessage());
        }
        borderPane.setCenter(anchorPane);

        if (currentMenuNum == 1) {
            menu1DisplayController = (Menu1DisplayController) fxmlLoader.getController();
        } else if (currentMenuNum == 2) {
            menu2DisplayController = (Menu2DisplayController) fxmlLoader.getController();
        } else if (currentMenuNum == 3) {
            menu3DisplayController = (Menu3DisplayController) fxmlLoader.getController();
        }
    }

    private String getCurrentViewerPath(int currentMenuNum) {
        currentViewerPath = pathList[currentMenuNum];
        return currentViewerPath;
    }

    @FXML
    private void handleBackButtonAction(ActionEvent event) {
        if (currentMenuNum == 0) {
            return;
        }
        currentMenuNum = currentMenuNum - 1;
        currentViewerPath = getCurrentViewerPath(currentMenuNum);
        setControlItems(currentViewerPath, currentMenuNum);
    }

    @FXML
    private void handleNextButtonAction(ActionEvent event) {
        currentMenuNum = currentMenuNum + 1;
        currentViewerPath = getCurrentViewerPath(currentMenuNum);
        setControlItems(currentViewerPath, currentMenuNum);
    }

    @FXML
    private void handleCheckButtonAction(ActionEvent event) {
        displayMassageLabel.setText("Welcome Menu " + currentMenuNum);
    }
}

StartDisplay.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1">
   <children>
      <VBox alignment="CENTER" layoutX="10.0" layoutY="10.0" prefHeight="361.0" prefWidth="600.0" spacing="20.0">
         <children>
            <Label text="Display Message" />
            <Label text="Start Display" />
            <Label fx:id="displayMassageLabel" />
         </children>
      </VBox>
   </children>
</AnchorPane>

Menu1DisplayController.java

package javafxapplication2;

import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.control.Label;

/**
 * FXML Controller class
 *
 * @author James
 */
public class Menu1DisplayController implements Initializable {
    @FXML
    private Label displayMassageLabel;

    /**
     * Initializes the controller class.
     */
    @Override
    public void initialize(URL url, ResourceBundle rb) {
        // TODO
    }   

    @FXML
    private void handleCheckButtonAction(ActionEvent event) {
        displayMassageLabel.setText("Welcome Menu 1");
    }

}

Menu1Display.fxml

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

<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>

<AnchorPane id="AnchorPane" prefHeight="400.0" prefWidth="600.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="javafxapplication2.Menu1DisplayController">
   <children>
      <VBox alignment="CENTER" layoutX="10.0" layoutY="10.0" prefHeight="361.0" prefWidth="600.0" spacing="20.0">
         <children>
            <Label text="Display Message" />
            <Label text="Current Menu is 1" />
            <Label fx:id="displayMassageLabel" />
         </children>
      </VBox>
   </children>
</AnchorPane>

FXML файловете и контролерите за меню 2 и 3 са същите като тези за меню 1. моля помогнете ми.

Това са грешки..

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1770)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1653)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:86)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:49)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Node.fireEvent(Node.java:8390)
    at javafx.scene.control.Button.fire(Button.java:185)
    at com.sun.javafx.scene.control.behavior.ButtonBehavior.mouseReleased(ButtonBehavior.java:182)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:96)
    at com.sun.javafx.scene.control.skin.BehaviorSkinBase$1.handle(BehaviorSkinBase.java:89)
    at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:238)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:191)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:59)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:56)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:114)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:74)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:54)
    at javafx.event.Event.fireEvent(Event.java:198)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3758)
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3486)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2495)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:350)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$350(GlassViewEventHandler.java:385)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$$Lambda$105/472212858.get(Unknown Source)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:404)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:384)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555)
    at com.sun.glass.ui.View.notifyMouse(View.java:927)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$145(WinApplication.java:101)
    at com.sun.glass.ui.win.WinApplication$$Lambda$36/1963387170.run(Unknown Source)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:497)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1765)
    ... 50 more
Caused by: java.lang.NullPointerException
    at javafxapplication2.MainController.handleCheckButtonAction(MainController.java:101)
    ... 60 more

person James    schedule 28.11.2015    source източник
comment
Възможно ли е да е липсващият етикет @FXML над displayMessageLabel?   -  person Inge    schedule 28.11.2015
comment
@FXML private Label displayMassageLabel; Вече добавих това преди. Но все още не работи   -  person James    schedule 28.11.2015
comment
Проблемът е в начина, по който инициализирате етикета. Деклариран е във всички fxml файлове с изключение на Main.fxml, но това е този, в който искате да го препратите, но той е null и следователно грешката. Или поставяте етикета в Main.fxml, или трябва да декларирате функция setMessageLabel във всички други контролери, които след това можете да извикате от MainController и да предадете стойността.   -  person Inge    schedule 28.11.2015
comment
След това, трябва ли да добавя още логика, за да реша кой контролер да вземе стойността, предадена от maincontroller? като например условия?   -  person James    schedule 29.11.2015


Отговори (1)


Добавяне на функция

public void setDisplayMessageLabel(String message){
     displayMassageLabel.setText(message);
}

към всички Menu1DisplayControllers (Menu1,Menu2,...). Знайте, че можете да извикате тази функция от вашия MainContorller като

@FXML
private void handleCheckButtonAction(ActionEvent event) {
   if (currentMenuNum == 1) {
        menu1DisplayController.setDisplayMassageLabel("Welcome Menu " + currentMenuNum;
    } else if (currentMenuNum == 2) {
        menu2DisplayController.setDisplayMassageLabel("Welcome Menu " + currentMenuNum;
    } else if (currentMenuNum == 3) {
        menu3DisplayController.setDisplayMassageLabel("Welcome Menu " + currentMenuNum;
    }

}
person Inge    schedule 29.11.2015