Unable to get Scene from MenuItem in JavaFX

后端 未结 3 1957
梦谈多话
梦谈多话 2020-12-19 03:22

I am trying to change the scene in a javafx stage based on menuItem click. Here is my sample.fxml:





        
相关标签:
3条回答
  • 2020-12-19 03:40

    Your real error is shown in the second to last line of the stack trace:

    Caused by: java.lang.ClassCastException: javafx.scene.control.MenuItem cannot be cast to javafx.scene.Node
        at sample.Controller.onTweetsMenuActionPerformed(Controller.java:29)
    

    This error is referring to the following line from your controller:

    Node node= (Node)event.getSource();
    

    Looking at the JavaFX API Docs, neither MenuItem nor Menu are subclasses of Node. http://docs.oracle.com/javafx/2/api/javafx/scene/control/MenuItem.html http://docs.oracle.com/javafx/2/api/javafx/scene/control/Menu.html

    I would suggest grabbing the source as an Object, then checking its type before continuing. Also, I ran into problems using the getSource() method; the getTarget() method worked better for me. Either way, you still need a way to get the to the Stage.

    To do this, you might want to use the fx:id tag in your FXML instead of the id tag. This will allow you to inject the FXML elements directly into your controller. For example, you could grab the Stage from the MenuBar (which is a subclass of Node) by injecting the MenuBar element into your controller.

    In the FXML:

    <MenuBar fx:id="myMenuBar" layoutY="0.0" maxWidth="1.7976931348623157E308" prefWidth="300.0" useSystemMenuBar="false" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="2.0">
    

    In the controller:

    public class Controller implements Initializable {
        @FXML MenuBar myMenuBar;
        ...
        @FXML
        protected void onTweetsMenuActionPerformed(ActionEvent event) {
            System.out.println("Manage Accbtnclick");
            Stage stage = (Stage) myMenuBar.getScene().getWindow();
            Scene scene = Main.screens.get("tweet");
            stage.setScene(scene);
            stage.show();
        }
        ...
    }
    

    You may need to do a bit of tweaking here, but hopefully it helps.

    0 讨论(0)
  • 2020-12-19 03:42

    Stage stage = (Stage) ((Node) myMenuBar).getScene().getWindow();

    0 讨论(0)
  • 2020-12-19 03:48

    Here is a way to get the Scene and Window based on a menu item being clicked without it being an injected FXML element, or without referencing it if you did create it with FXML. In other words by using the Event's target.

    In my problem I had a MenuButton with a dropdown menu (a ContextMenu as I found out, which I didn't know as I had created my menu in FXML) containing MenuItems and I wanted to open a FileChooser, which needs the Window as an argument, when the "Save" MenuItem was clicked.

    Normally I would have gone down the route of getting the event's target, then the Parent, then the next Parent etc. and finally the Scene and then Window. As Menu and MenuItem are not Nodes and therefore do not have Parents In this case however I did the following:

    FileChooser fileChooser = new FileChooser();
    
    MenuItem menuItem = (MenuItem)event.getTarget();
    ContextMenu cm = menuItem.getParentPopup();
    Scene scene = cm.getScene();
    Window window = scene.getWindow();
    
    fileChooser.showSaveDialog(window);
    

    Or, converting the bulk into a one line argument:

    FileChooser fileChooser = new FileChooser();
    
    fileChooser.showSaveDialog(((MenuItem)event.getTarget()).getParentPopup().getScene().getWindow());
    

    Just adapt this as necessary based on your own scene-graph (i.e. how many parents you need to get through in cases of sub-menus etc) and what you are wanting to do once you have the Window, but once you get to the ContextMenu (the popup list of MenuItems), you can get the Scene and then from that get the Window.




    As an aside, here is the FXML I used to create my MenuButton, and hence why I didn't realise I had to get the ContextMenu through a call to getParentPopup() without some trial and error:

    <MenuButton fx:id="menu" maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" mnemonicParsing="false" prefHeight="34.0" prefWidth="35.0" style="-fx-background-color: #6600ff; -fx-border-width: 0; -fx-mark-color: white; -fx-padding: 5;" textAlignment="CENTER" textFill="WHITE" underline="true">
        <items>
            <MenuItem fx:id="newSearch" mnemonicParsing="false" text="New Search" onAction="#clearSearch" />
            <SeparatorMenuItem  />
            <MenuItem fx:id="saveSearch" mnemonicParsing="false" text="Save Search" onAction="#saveSearch" />
            <MenuItem fx:id="loadSearch" mnemonicParsing="false" text="Load Search" />
            <SeparatorMenuItem  />
            <MenuItem fx:id="saveResults" mnemonicParsing="false" text="Save Results" />
            <MenuItem fx:id="loadResults" mnemonicParsing="false" text="Load Results" />
            <SeparatorMenuItem />
            <MenuItem fx:id="exportResults" mnemonicParsing="false" text="Export Results" />
        </items>
        <font>
            <Font name="Arial" size="12.0" />
        </font>
    </MenuButton>
    
    0 讨论(0)
提交回复
热议问题