user2168435
user2168435

Reputation: 762

JavaFX error with changing scene multiple times

The goal is to use action events to change the scene based on the menu selection.

This works file for the first change:

After that i get the below exception thrown, is there something wrong with my code preventing it from working ?

Exception in thread "JavaFX Application Thread" java.lang.IllegalArgumentException: The owner node needs to be associated with a window
at javafx.stage.PopupWindow.show(PopupWindow.java:384)
at javafx.scene.control.ContextMenu.doShow(ContextMenu.java:287)
at javafx.scene.control.ContextMenu.show(ContextMenu.java:262)
at com.sun.javafx.scene.control.skin.MenuButtonSkinBase.show(MenuButtonSkinBase.java:171)
at com.sun.javafx.scene.control.skin.MenuButtonSkinBase.handleControlPropertyChanged(MenuButtonSkinBase.java:199)
at com.sun.javafx.scene.control.skin.BehaviorSkinBase.lambda$registerChangeListener$61(BehaviorSkinBase.java:197)
at com.sun.javafx.scene.control.MultiplePropertyChangeListenerHandler$1.changed(MultiplePropertyChangeListenerHandler.java:55)
at javafx.beans.value.WeakChangeListener.changed(WeakChangeListener.java:89)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at javafx.scene.control.MenuButton.setShowing(MenuButton.java:218)
at javafx.scene.control.MenuButton.show(MenuButton.java:286)
at com.sun.javafx.scene.control.skin.MenuBarSkin.lambda$rebuildUI$398(MenuBarSkin.java:641)
at com.sun.javafx.binding.ExpressionHelper$Generic.fireValueChangedEvent(ExpressionHelper.java:361)
at com.sun.javafx.binding.ExpressionHelper.fireValueChangedEvent(ExpressionHelper.java:81)
at javafx.beans.property.ReadOnlyBooleanPropertyBase.fireValueChangedEvent(ReadOnlyBooleanPropertyBase.java:72)
at javafx.beans.property.ReadOnlyBooleanWrapper.fireValueChangedEvent(ReadOnlyBooleanWrapper.java:103)
at javafx.beans.property.BooleanPropertyBase.markInvalid(BooleanPropertyBase.java:110)
at javafx.beans.property.BooleanPropertyBase.set(BooleanPropertyBase.java:144)
at javafx.scene.control.Menu.setShowing(Menu.java:210)
at javafx.scene.control.Menu.show(Menu.java:408)
at com.sun.javafx.scene.control.skin.MenuBarSkin.lambda$rebuildUI$401(MenuBarSkin.java:677)
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.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)

Code

 public void start(Stage primaryStage) throws Exception {

    AnchorPane pane = (AnchorPane) FXMLLoader.load(getClass().getClassLoader().getResource("panel.fxml"));
    AnchorPane pane2 = (AnchorPane) FXMLLoader.load(getClass().getClassLoader().getResource("panel2.fxml"));

    MenuBar menuBar = new MenuBar();
    MenuBar menuBar2 = new MenuBar();

    Menu file = new Menu("File");
    MenuItem home = new MenuItem("home");
    home.setOnAction(e -> primaryStage.setScene(sceneHome));
    MenuItem last20 = new MenuItem("last 20");
    last20.setOnAction(e -> primaryStage.setScene(scene2));
    MenuItem exit = new MenuItem("exit");
    exit.setOnAction(actionEvent -> Platform.exit());

    file.getItems().addAll(home,last20,new SeparatorMenuItem(),exit);

    menuBar.getMenus().addAll(file);
    menuBarTrans.getMenus().addAll(file);

    sceneHome = new Scene(new VBox(menuBar,pane));
    scene2 = new Scene(new VBox(menuBar2,pane2));

    primaryStage.setScene(scene2);
    primaryStage.setResizable(false);
    primaryStage.show();
}

Upvotes: 3

Views: 1304

Answers (1)

DVarga
DVarga

Reputation: 21829

You should not change the scenes. Instead, update a part of the Scene with the Parent returned by the FXMLLoader.

What you can see in the example: It uses a single screen having a BorderPane as root. The top element of the border pane is a static MenuBar and on selection of this menu bar, the center element of the border pane is updated with the root Parent object returned by the corresponding FXMLLoader.

@Override
public void start(Stage primaryStage) {
    try {
        BorderPane root = new BorderPane();
        Scene scene = new Scene(root, 400, 400);

        FXMLLoader loader1 = new FXMLLoader(getClass().getResource("panel.fxml"));
        AnchorPane pane1 = loader1.load();
        FXMLLoader loader2 = new FXMLLoader(getClass().getResource("panel2.fxml"));
        AnchorPane pane2 = loader2.load();

        // Create the MenuBar
        MenuBar menuBar = new MenuBar();

        Menu file = new Menu("File");
        MenuItem home = new MenuItem("Home");
        home.setOnAction(e -> root.setCenter(pane1));
        MenuItem last20 = new MenuItem("last 20");
        last20.setOnAction(e -> root.setCenter(pane2));

        MenuItem exit = new MenuItem("exit");
        exit.setOnAction(actionEvent -> Platform.exit());

        file.getItems().addAll(home,last20,new SeparatorMenuItem(),exit);

        menuBar.getMenus().addAll(file);

        // Top is always the MenuBar
        root.setTop(menuBar);
        // Load Home on startup
        root.setCenter(pane1);

        primaryStage.setScene(scene);

        primaryStage.setResizable(false);
        primaryStage.show();
    } catch(Exception e) {
        e.printStackTrace();
    }
}

Upvotes: 2

Related Questions