Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
1.2k views
in Technique[技术] by (71.8m points)

java - Unable to get Scene from MenuItem in JavaFX

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

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

<?import java.lang.*?>
<?import java.net.*?>
<?import javafx.geometry.Insets?>
<?import javafx.scene.control.*?>
<?import javafx.scene.control.Button?>
<?import javafx.scene.control.Label?>
<?import javafx.scene.image.*?>
<?import javafx.scene.layout.*?>
<?import javafx.scene.layout.GridPane?>

<AnchorPane prefHeight="-1.0" prefWidth="560.0" styleClass="background" xmlns:fx="http://javafx.com/fxml/1" xmlns="http://javafx.com/javafx/2.2" fx:controller="sample.Controller">
  <children>
    <MenuBar layoutY="0.0" maxWidth="1.7976931348623157E308" prefWidth="300.0" useSystemMenuBar="false" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="2.0">
      <menus>
        <Menu id="manageAccountsMenu" mnemonicParsing="false" onAction="#onManageAccountsMenuActionPerformed" text="Accounts" fx:id="manageAccountsMenu">
          <items>
            <MenuItem mnemonicParsing="false" onAction="#onTweetsMenuActionPerformed" text="Manage" fx:id="manageAccountsSubmenuItem" />
          </items>
        </Menu>
        <Menu mnemonicParsing="false" onAction="#onTweetsMenuActionPerformed" text="Tweets" fx:id="tweetsMenuItem" />
        <Menu mnemonicParsing="false" text="Retweets" />
      </menus>
    </MenuBar>
    <VBox id="VBox" alignment="CENTER" layoutY="24.0" spacing="5.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0">
      <children>
        <ScrollPane id="ScrollPane" fitToHeight="true" fitToWidth="true" prefViewportHeight="400.0" prefViewportWidth="300.0">
          <content>
            <TableView prefHeight="-1.0" prefWidth="-1.0" tableMenuButtonVisible="true">
              <columns>
                <TableColumn editable="false" prefWidth="75.0" text="SNO" />
                <TableColumn prefWidth="200.0" text="Account" />
                <TableColumn prefWidth="200.0" text="Status" />
                <TableColumn prefWidth="75.0" text="Actions" />
              </columns>
            </TableView>
          </content>
        </ScrollPane>
        <Button mnemonicParsing="false" text="Add Account" textAlignment="CENTER">
          <graphic>
            <ImageView fitHeight="150.0" fitWidth="200.0" mouseTransparent="true" pickOnBounds="true" preserveRatio="true">
              <image>
                <Image url="@addAccount.png" />
              </image>
            </ImageView>
          </graphic>
        </Button>
      </children>
    </VBox>
  </children>
  <stylesheets>
    <URL value="@darkTheme.css" />
  </stylesheets>
</AnchorPane>

Here is my Controller.java:

package sample;

import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.Initializable;
import javafx.scene.Node;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
import javafx.stage.Stage;

import java.net.URL;
import java.util.ResourceBundle;

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

    @Override
    public void initialize(URL url, ResourceBundle resourceBundle) {
        //To change body of implemented methods use File | Settings | File Templates.
    }
}

Here is my Main.java:

package sample;

import javafx.application.Application;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Group;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.ProgressBar;
import javafx.scene.control.ProgressIndicator;
import javafx.scene.layout.HBox;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

import java.io.IOException;
import java.util.HashMap;

public class Main extends Application {

    public static HashMap<String,Scene> screens=new HashMap<String,Scene>();

    @Override
    public void start(Stage stage) {
        try {
            Parent accountScreen= FXMLLoader.load(getClass().getResource("sample.fxml"));
            Parent tweetScreen=FXMLLoader.load(getClass().getResource("tweetform.fxml"));
            //Parent retweetScreen=FXMLLoader.load(getClass().getResource("retweetform.fxml"));
            screens.put("account",new Scene(accountScreen));
            screens.put("tweet",new Scene(tweetScreen));
            //screens.put("retweet",new Scene(retweetScreen));
            stage.setTitle("Manage Accounts");
            stage.setScene(screens.get("account"));
            stage.show();
        } catch (IOException e) {
            e.printStackTrace();  //To change body of catch statement use File | Settings | File Templates.
        }

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

When I click on the menuItem Manage under Accounts Menu, I get the following exception:

    "C:Program FilesJavajdk1.7.0_17injava" -Didea.launcher.port=7541 "-Didea.launcher.bin.path=C:Program Files (x86)JetBrainsIntelliJ IDEA 12.1.4in" -Dfile.encoding=UTF-8 -classpath "C:Program FilesJavajdk1.7.0_17jrelibcharsets.jar;C:Program FilesJavajdk1.7.0_17jrelibdeploy.jar;C:Program FilesJavajdk1.7.0_17jrelibjavaws.jar;C:Program FilesJavajdk1.7.0_17jrelibjce.jar;C:Program FilesJavajdk1.7.0_17jrelibjfr.jar;C:Program FilesJavajdk1.7.0_17jrelibjfxrt.jar;C:Program FilesJavajdk1.7.0_17jrelibjsse.jar;C:Program FilesJavajdk1.7.0_17jrelibmanagement-agent.jar;C:Program FilesJavajdk1.7.0_17jrelibplugin.jar;C:Program FilesJavajdk1.7.0_17jrelib
esources.jar;C:Program FilesJavajdk1.7.0_17jrelib
t.jar;C:Program FilesJavajdk1.7.0_17jrelibextaccess-bridge-64.jar;C:Program FilesJavajdk1.7.0_17jrelibextdnsns.jar;C:Program FilesJavajdk1.7.0_17jrelibextjaccess.jar;C:Program FilesJavajdk1.7.0_17jrelibextlocaledata.jar;C:Program FilesJavajdk1.7.0_17jrelibextsunec.jar;C:Program FilesJavajdk1.7.0_17jrelibextsunjce_provider.jar;C:Program FilesJavajdk1.7.0_17jrelibextsunmscapi.jar;C:Program FilesJavajdk1.7.0_17jrelibextzipfs.jar;C:Users
ahulserverIdeaProjectsDrawingTextoutproductionDrawingText;C:Program Files (x86)JetBrainsIntelliJ IDEA 12.1.4libidea_rt.jar" com.intellij.rt.execution.application.AppMain sample.Main
Manage Accbtnclick
Manage Accbtnclick
java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1440)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:28)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.control.MenuItem.fire(MenuItem.java:456)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1188)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1139)
    at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$6.handle(ContextMenuContent.java:1137)
    at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:69)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:217)
    at com.sun.javafx.event.EventHandlerManager.dispatchBubblingEvent(EventHandlerManager.java:170)
    at com.sun.javafx.event.CompositeEventDispatcher.dispatchBubblingEvent(CompositeEventDispatcher.java:38)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:37)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:35)
    at com.sun.javafx.event.EventDispatchChainImpl.dispatchEvent(EventDispatchChainImpl.java:92)
    at com.sun.javafx.event.EventUtil.fireEventImpl(EventUtil.java:53)
    at com.sun.javafx.event.EventUtil.fireEvent(EventUtil.java:33)
    at javafx.event.Event.fireEvent(Event.java:171)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3328)
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3168)
    at javafx.scene.Scene$MouseHandler.access$1900(Scene.java:3123)
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1563)
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2265)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:250)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:173)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:292)
    at com.sun.glass.ui.View.handleMouseEvent(View.java:528)
    at com.sun.glass.ui.View.notifyMouse(View.java:922)
    at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.access$100(WinApplication.java:29)
    at com.sun.glass.ui.win.WinApplication$3$1.run(WinApplication.java:73)
    at java.lang.Thread.run(Thread.java:722)
Caused by: java.lang.reflect.InvocationTargetException
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:55)
    at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.lang.reflect.Method.invoke(Method.java:601)
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:269)
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1435)
    ... 40 more
Caused by: java.lang.ClassCastException: javafx.scene.control.MenuItem cannot be cast to javafx.scene.Node
    at sample.Controller.onTweetsMenuActionPerformed(Controller.java:29)

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

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.


与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...