无法从JavaFX中的MenuItem获取场景

我试图基于menuItem单击更改javafx阶段中的场景。 这是我的sample.fxml:

                                             

这是我的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. } } 

这是我的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 screens=new HashMap(); @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); } } 

当我点击Accounts Menu下的menuItem Manage时,我得到以下exception:

  "C:\Program Files\Java\jdk1.7.0_17\bin\java" -Didea.launcher.port=7541 "-Didea.launcher.bin.path=C:\Program Files (x86)\JetBrains\IntelliJ IDEA 12.1.4\bin" -Dfile.encoding=UTF-8 -classpath "C:\Program Files\Java\jdk1.7.0_17\jre\lib\charsets.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\deploy.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\javaws.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jce.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jfr.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jfxrt.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\jsse.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\management-agent.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\plugin.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\resources.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\rt.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\access-bridge-64.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\dnsns.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\jaccess.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\localedata.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\sunec.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\sunjce_provider.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\sunmscapi.jar;C:\Program Files\Java\jdk1.7.0_17\jre\lib\ext\zipfs.jar;C:\Users\rahulserver\IdeaProjects\DrawingText\out\production\DrawingText;C:\Program Files (x86)\JetBrains\IntelliJ IDEA 12.1.4\lib\idea_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) ... 50 more 

那么如何从菜单项单击事件处理程序中获取包含的舞台/场景?

编辑该行

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

在controller.java中是行号29,它给出了问题。

您的实际错误显示在堆栈跟踪的倒数第二行:

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

此错误指的是您的控制器中的以下行:

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

查看JavaFX API文档,MenuItem和Menu都不是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

我建议将源作为Object抓取,然后在继续之前检查其类型。 另外,我遇​​到了使用getSource()方法的问题; getTarget()方法对我来说效果更好。 无论哪种方式,你仍然需要一种方法来进入舞台。

为此,您可能希望在FXML中使用fx:id标记而不是id标记。 这将允许您将FXML元素直接注入控制器。 例如,您可以通过将MenuBar元素注入控制器,从MenuBar(它是Node的子类)中获取舞台。

在FXML中:

  

在控制器中:

 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(); } ... } 

你可能需要在这里做一些调整,但希望它有所帮助。

这是一种基于单击的菜单项获取SceneWindow方法,而不是注入的FXML元素,或者如果您使用FXML创建它,则不引用它。 换句话说,通过使用Event的目标。

在我的问题中,我有一个带有下拉菜单的MenuButton (我发现的一个ContextMenu ,我不知道,因为我在FXML中创建了我的菜单),包含MenuItems ,我想打开一个FileChooser ,它需要Window作为参数,单击“保存” MenuItem时。

通常我会沿着获取事件目标的路线,然后是父,然后是下一个父等,最后是场景,然后是窗口。 由于MenuMenuItem不是Node ,因此没有Parent s在这种情况下,我做了以下内容:

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

或者,将批量转换为单行参数:

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

根据您自己的场景图(即在子菜单的情况下您需要通过多少父母等)以及在您拥有Window想要做的事情,只需根据需要进行调整,但是一旦到达ContextMenuMenuItems的弹出列表),您可以获取Scene ,然后从中获取Window

顺便说一句,这里是我用来创建我的MenuButton的FXML,因此我没有意识到我必须通过调用getParentPopup()来获取ContextMenu而不需要一些试验和错误:

                 

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