我正试图在javafx阶段中根据菜单项单击来更改场景。这是我的示例.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>
这是我的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<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);
}
}
当我点击账户菜单下的项目管理菜单时,我会得到以下异常:
"C:Program FilesJavajdk1.7.0_17binjava" -Didea.launcher.port=7541 "-Didea.launcher.bin.path=C:Program Files (x86)JetBrainsIntelliJ IDEA 12.1.4bin" -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_17jrelibresources.jar;C:Program FilesJavajdk1.7.0_17jrelibrt.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:UsersrahulserverIdeaProjectsDrawingTextoutproductionDrawingText;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)
... 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.htmlhttp://docs.oracle.com/javafx/2/api/javafx/scene/control/Menu.html
我建议将源作为Object获取,然后在继续之前检查其类型。此外,我在使用getSource()方法时遇到了问题;getTarget()方法对我来说效果更好。不管怎样,你仍然需要一种方法来将。
为此,您可能需要在FXML中使用fx:id
标记,而不是id
标记。这将允许您将FXML元素直接注入控制器。例如,您可以通过将MenuBar元素注入控制器来从MenuBar(它是Node的子类)中获取Stage。
在FXML中:
<MenuBar fx:id="myMenuBar" layoutY="0.0" maxWidth="1.7976931348623157E308" prefWidth="300.0" useSystemMenuBar="false" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="2.0">
在控制器中:
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();
}
...
}
你可能需要在这里做一些调整,但希望它能有所帮助。
在JavaFX 15.0.1中,您可以使用getOwnerWindow来获取舞台和舞台上的场景。
Stage owner = (Stage)menuItem.getParentPopup().getOwnerWindow();
Scene scene = owner.getScene();
这里有一种方法可以根据单击的菜单项获得Scene
和Window
,而不需要将其作为注入的FXML元素,或者如果您确实使用FXML创建了它,则不需要引用它。换句话说,使用Event
的目标。
在我的问题中,我有一个MenuButton
,它有一个包含MenuItems
的下拉菜单(我发现的是ContextMenu
,因为我在FXML中创建了菜单,所以我不知道它),并且我想打开一个需要Window
作为参数的FileChooser
,当;保存";单击了MenuItem
。
通常情况下,我会沿着获取事件目标的路线,然后是父对象,然后是下一个父对象等,最后是场景,然后是窗口。由于Menu
和MenuItem
不是Node
s,因此没有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
,您想做什么来进行必要的调整,但一旦您到达ContextMenu
(MenuItems
的弹出列表),您就可以获得Scene
,然后从中获得Window
。
顺便说一句,这是我用来创建MenuButton
的FXML,因此我没有意识到我必须通过对getParentPopup()
的调用来获得ContextMenu
,而不需要一些尝试和错误:
<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>
Stage Stage=(Stage)((Node)myMenuBar).getScene().getWindow();