JavaFX:如何从 MenuItem 更改场景 (FXML)
Posted
技术标签:
【中文标题】JavaFX:如何从 MenuItem 更改场景 (FXML)【英文标题】:JavaFX: How to change scene (FXML) from MenuItem 【发布时间】:2022-01-09 03:34:34 【问题描述】:在 76 岁时,我正在努力学习 Java,并制作了许多与会计相关的教程,这些教程成功地改变了场景。现在来看一个使用菜单栏和菜单项的结构,以应对将 14 个章节链接为菜单栏上的一项。
我看过/看过的所有示例都显示了每个MenuItem
的简单println
。我的这个工作正常,但是当我尝试从我以前的应用程序中复制我的 FXMLLoader
时,它不喜欢它。
我得到这个找不到符号:symbol: method getScene() location: variable mbarchapter1 of type MenuItem
我的代码是:
package accountingsnapshots;
import java.io.IOException;
import java.net.URL;
import java.util.ResourceBundle;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.fxml.Initializable;
import javafx.scene.Parent;
import javafx.scene.Scene;
import javafx.scene.control.MenuItem;
import javafx.stage.Stage;
public class AccountingSnapshotsController implements Initializable
@FXML
private MenuItem mbarhome;
@FXML
private MenuItem mbarchapter1;
@FXML
private MenuItem mbarchapter2;
@FXML
private MenuItem mbarchapter3;
@FXML
private MenuItem mbarchapter4;
@FXML
private MenuItem mbarcalculator;
@FXML
private MenuItem mbarglossary;
@FXML
private MenuItem mbarhelp;
Stage stage;
@FXML Parent root;
@FXML
private void handleButtonAction(ActionEvent e) throws IOException
if(e.getSource()==mbarhome)
System.out.println("this is Home");
else if(e.getSource()==mbarchapter1)
System.out.println("this is chap 1");
//get reference to the button's stage
stage = (Stage) root.getScene().getWindow();
//load up OTHER FXML document
root = FXMLLoader.load(getClass().getResource("AccountingSnapshots_1.fxml"));
//create a new scene with root and set the stage
Scene scene = new Scene(root);
stage.setScene(scene);
stage.show();
else if(e.getSource()==mbarchapter2)
System.out.println("this is chap 2");
else if(e.getSource()==mbarchapter3)
System.out.println("this is chap 3");
else if(e.getSource()==mbarchapter4)
System.out.println("this is chap 4");
else if(e.getSource()==mbarcalculator)
System.out.println("this is Calculator");
else if(e.getSource()==mbarglossary)
System.out.println("this is Glossary");
else if(e.getSource()==mbarhelp)
System.out.println("this is Help");
@Override
public void initialize(URL url, ResourceBundle rb)
// TODO
我的 FXML 文件具有针对 menuItems 的 fx:ids。如下图:
<?xml version="1.0" encoding="UTF-8"?>
<?import javafx.scene.text.*?>
<?import java.lang.*?>
<?import java.util.*?>
<?import javafx.scene.*?>
<?import javafx.scene.control.*?>
<?import javafx.scene.layout.*?>
<AnchorPane id="AnchorPane" prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="accountingsnapshots.AccountingSnapshotsController">
<children>
<MenuBar layoutY="-1.0" prefHeight="30.0" prefWidth="858.0">
<menus>
<Menu fx:id="mbarhome" mnemonicParsing="false" onAction="#handleButtonAction" text="Home">
<items>
<MenuItem mnemonicParsing="false" text="Home" />
</items>
</Menu>
<Menu mnemonicParsing="false" text="Chapters">
<items>
<MenuItem fx:id="mbarchapter1" mnemonicParsing="false" onAction="#handleButtonAction" text="Ch.1 - Introduction to final accounts" />
<MenuItem fx:id="mbarchapter2" mnemonicParsing="false" onAction="#handleButtonAction" text="Ch.2 - Double entry bookkeeping" />
<MenuItem fx:id="mbarchapter3" mnemonicParsing="false" onAction="#handleButtonAction" text="Ch.3 - Accounting adjustments" />
<MenuItem fx:id="mbarchapter4" mnemonicParsing="false" onAction="#handleButtonAction" text="Ch.4 - Introduction to final accounts" />
</items>
</Menu>
<Menu fx:id="mbarcalculator" mnemonicParsing="false" onAction="#handleButtonAction" text="Calculator">
<items>
<MenuItem mnemonicParsing="false" text="Calculator" />
</items>
</Menu>
<Menu fx:id="mbarglossary" mnemonicParsing="false" onAction="#handleButtonAction" text="Glossary">
<items>
<MenuItem mnemonicParsing="false" text="Glossary" />
</items>
</Menu>
<Menu fx:id="mbarhelp" mnemonicParsing="false" onAction="#handleButtonAction" text="Help">
<items>
<MenuItem mnemonicParsing="false" text="Help" />
</items>
</Menu>
</menus>
</MenuBar>
</children>
</AnchorPane>
这是运行应用程序时的输出:
Created dir: C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\empty
Created dir: C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\generated-sources\ap-source-output
Compiling 2 source files to C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\classes
Copying 5 files to C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\classes
compile:
Created dir: C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist
Detected JavaFX Ant API version 1.3
Launching <fx:jar> task from C:\Program Files\Java\jdk1.8.0_31\jre\..\lib\ant-javafx.jar
Warning: From JDK7u25 the Codebase manifest attribute should be used to restrict JAR repurposing.
Please set manifest.custom.codebase property to override the current default non-secure value '*'.
Launching <fx:deploy> task from C:\Program Files\Java\jdk1.8.0_31\jre\..\lib\ant-javafx.jar
jfx-deployment-script:
jfx-deployment:
jar:
Copying 12 files to C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist\run53408212
jfx-project-run:
Executing C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist\run53408212\AccountingSnapshots.jar using platform C:\Program Files\Java\jdk1.8.0_31\jre/bin/java
this is chap 1
Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1762)
at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1645)
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.BasicEventDispatcher.dispatchEvent(BasicEventDispatcher.java:58)
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:49)
at javafx.event.Event.fireEvent(Event.java:198)
at javafx.scene.control.MenuItem.fire(MenuItem.java:462)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.doSelect(ContextMenuContent.java:1364)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer.lambda$createChildren$324(ContextMenuContent.java:1317)
at com.sun.javafx.scene.control.skin.ContextMenuContent$MenuItemContainer$$Lambda$147/1926554713.handle(Unknown Source)
at com.sun.javafx.event.CompositeEventHandler$NormalEventHandlerRecord.handleBubblingEvent(CompositeEventHandler.java:218)
at com.sun.javafx.event.CompositeEventHandler.dispatchBubblingEvent(CompositeEventHandler.java:80)
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)
at javafx.scene.Scene$MouseHandler.process(Scene.java:3724)
at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3452)
at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1728)
at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2461)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:348)
at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:273)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:382)
at com.sun.glass.ui.View.handleMouseEvent(View.java:553)
at com.sun.glass.ui.View.notifyMouse(View.java:925)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.lambda$null$141(WinApplication.java:102)
at com.sun.glass.ui.win.WinApplication$$Lambda$37/96639997.run(Unknown Source)
at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.reflect.InvocationTargetException
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.Trampoline.invoke(MethodUtil.java:71)
at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:483)
at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275)
at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1757)
... 43 more
Caused by: javafx.fxml.LoadException:
file:/C:/Users/john/Documents/NetBeansProjects/AccountingSnapshots/dist/run53408212/AccountingSnapshots.jar!/accountingsnapshots/AccountingSnapshots_1.fxml:16
at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2595)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2573)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2435)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3208)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3169)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3142)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3118)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3098)
at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3091)
at accountingsnapshots.AccountingSnapshotsController.handleButtonAction(AccountingSnapshotsController.java:53)
... 53 more
Caused by: java.lang.IllegalArgumentException: Unable to coerce MenuButton@35398aab[styleClass=menu-button]'Home' to class javafx.scene.control.MenuItem.
at com.sun.javafx.fxml.BeanAdapter.coerce(BeanAdapter.java:495)
at javafx.fxml.FXMLLoader$PropertyElement.add(FXMLLoader.java:1387)
at javafx.fxml.FXMLLoader$ValueElement.processEndElement(FXMLLoader.java:784)
at javafx.fxml.FXMLLoader.processEndElement(FXMLLoader.java:2817)
at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2526)
... 61 more
更正了第二个 .fxml 文件,将 MenuButton 更改为 MenuItem。这是输出部分的结果:
ant -f C:\\Users\\john\\Documents\\NetBeansProjects\\AccountingSnapshots jfxsa-run
init:
Deleting: C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\built-jar.properties
deps-jar:
Updating property file: C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\build\built-jar.properties
compile:
Detected JavaFX Ant API version 1.3
jfx-deployment:
jar:
Copying 12 files to C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist\run581163156
jfx-project-run:
Executing C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist\run581163156\AccountingSnapshots.jar using platform C:\Program Files\Java\jdk1.8.0_31\jre/bin/java
this is chap 1
Deleting directory C:\Users\john\Documents\NetBeansProjects\AccountingSnapshots\dist\run581163156
jfxsa-run:
BUILD SUCCESSFUL (total time: 19 seconds)
任何帮助表示赞赏
【问题讨论】:
您想在单击 MenuItem 时使用 FXML 打开一个新窗口吗?或者只是在现有场景的一部分中加载 FXML? 当我选择 B 以加粗代码中的项目时,getScene 周围的双星号。 getScene 谢谢。我想打开一个新窗口。 那么问题已经回答了:) 你检查过this answer ?? 【参考方案1】:MenuItem
不是Node
的子类,因此它不会继承getScene()
method。
最简单的解决方案是在您知道与包含菜单项的菜单栏位于同一场景中的任何场景图节点上调用getScene()
。
stage = (Stage) someNode.getScene().getWindow();
其中someNode
是您使用@FXML
注入控制器的任何Node
。
由于您目前只有MenuItem
s 注入到您的控制器中,因此您需要为此注入一些节点。最自然的就是 FXML 的根。为此,将fx:id="root"
属性添加到FXML 的根元素,然后只需更改控制器中root
字段的声明,以便注入:
@FXML
private Parent root ;
然后
stage = (Stage) root.getScene().getWindow();
应根据需要为您提供当前的Stage
。
【讨论】:
非常感谢你们两位的帮助。我想我已经添加了 fx:ids - 但为了帮助我添加了我的 .fxml 文件。 将fx:id="root"
添加到您的 fxml 中的 AnchorPane 声明中,并在他的回答中按照@James_D 编辑。
好的,我已将 fx:id="root" 添加到 AnchorPane 声明中。仍然得到 System.out.println - 但它不会加载新的 .fxml。我在输出中得到以下内容: Caused by: java.lang.NullPointerException at accountingsnapshots.AccountingSnapshotsController.handleButtonAction(AccountingSnapshotsController.java:51)
stage = (Stage) root.getScene().getWindow();
无法从那里诊断。看起来它正在运行,没有错误。我建议您创建一个simple, complete example that others can run 并发布它 - 可能是在一个新问题中,因为这里的原始问题(“找不到符号”)实际上已经解决了。 (无论如何,您可能会发现创建简单示例的过程会引导您发现解决方案。)【参考方案2】:
这是一个旧线程,但给出的答案是正确的
这里有一些代码供任何面临相同问题的人使用
通常,我只会将一个节点传递给舞台对象,但正如已经说明的那样 - 菜单/菜单项不能转换为节点。使用最外层节点的 fx:id 可以解决问题。 reportAnchorpane 是相应 FXML 的(根)节点的名称
public void gotoReports(ActionEvent e) throws IOException
FXMLLoader loader = new FXMLLoader();
loader.setLocation(getClass().getResource("/Reports/Reports.fxml"));
Parent ReportManager = loader.load();
Scene ReportManagerScene = new Scene(ReportManager);
Stage window = (Stage)reportAnchorPane.getScene().getWindow();
window.setScene(ReportManagerScene);
window.show();
关于 FXML
<AnchorPane fx:id="reportAnchorPane" prefHeight="500.0" prefWidth="800.0" styleClass="mainFxmlClass" fx:controller="Reports.ReportsController">
<stylesheets>
<URL value="@reports.css" />
</stylesheets>
<children>
<HBox fx:id="Menu" prefHeight="25.0" prefWidth="925.0">
<children>
<MenuBar fx:id="MenuBar" prefHeight="25.0" prefWidth="925.0">
<menus>
<Menu mnemonicParsing="false" text="Window" >
<items>
<MenuItem fx:id="miGotoReportsPage" mnemonicParsing="false" text="Reports" onAction="#gotoReports"/>
</items>
</Menu>
</menus>
</MenuBar>
</children>
</HBox>
</children>
</AnchorPane>
【讨论】:
以上是关于JavaFX:如何从 MenuItem 更改场景 (FXML)的主要内容,如果未能解决你的问题,请参考以下文章