3

At 76, I am trying to learn Java and have produced a number of accounting related tutorials that successfully change scenes. Now looking at a structure using menubar and menu items to cope with linking 14 chapters as one of the items on the menubar.

All examples I have seen/watched show a simple println for each MenuItem. I have this working OK, but when I try to copy my FXMLLoader from my previous applications it doesn't like it.

I get this cannot find symbol: symbol: method getScene() location: variable mbarchapter1 of type MenuItem

My code is:

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
    }    

}

My FXML file has fx:ids against the menuItems. Shown below:

    <?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>

This is the output when running the application:

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

Corrected the second .fxml file, changing MenuButton to MenuItem. This is the result in the output section:

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)

Any help appreciated

2 Answers2

4

MenuItem is not a subclass of Node, so it doesn't inherit a getScene() method.

The simplest solution is just to call getScene() on any scene graph node which you know to be in the same scene as the menubar containing your menu item.

stage = (Stage) someNode.getScene().getWindow();

where someNode is any Node that you have injected into your controller with @FXML.

As you currently only have MenuItems injected into your controller, you need to inject some node for this purpose. The most natural one would be the root of the FXML. To do this, add a fx:id="root" attribute to your FXML's root element, and then just change the declaration of the root field in the controller so that it is injected:

@FXML
private Parent root ;

Then

stage = (Stage) root.getScene().getWindow();

should give you the current Stage, as needed.

James_D
  • 201,275
  • 16
  • 291
  • 322
  • Many thanks to both of you for your help. I think I have fx:ids added - but to help I have added my .fxml file. –  Apr 13 '15 at 14:09
  • Add `fx:id="root"` to the AnchorPane declaration in your fxml and follow @James_D edit in his answer. – ItachiUchiha Apr 13 '15 at 14:11
  • OK, I have added fx:id="root" to the AnchorPane declaration. Still get the System.out.println - but it doesn't load the new .fxml. I get the following in the output: Caused by: java.lang.NullPointerException at accountingsnapshots.AccountingSnapshotsController.handleButtonAction(AccountingSnapshotsController.java:51) –  Apr 13 '15 at 14:36
  • stage = (Stage) root.getScene().getWindow(); –  Apr 13 '15 at 14:40
  • And you have the `@FXML` annotation on `root`? – James_D Apr 13 '15 at 14:45
  • This is the anchor pane line from my .fxml showing the fx:id="root". –  Apr 13 '15 at 14:49
  • What do you mean @FXML annotation? –  Apr 13 '15 at 14:57
  • Did you add the `@FXML` annotation to the declaration of `root` in the controller, as in the code in the answer? – James_D Apr 13 '15 at 14:58
  • In my controller, I have declared Parent root; Tried to add @FXML to that but I lose the Parent declaration. –  Apr 13 '15 at 15:12
  • I don't understand "I lose the `Parent` declaration`". – James_D Apr 13 '15 at 15:16
  • Going back to your earlier "Did you update the controller with the @FXML annotation?". Please give me an example of exactly what you mean. I am struggling a bit here. –  Apr 13 '15 at 15:20
  • The code is already in the answer. Replace your declaration `Parent root;` with `@FXML private Parent root;`. (`private` is optional, but generally preferred.) – James_D Apr 13 '15 at 15:24
  • Thanks again. I had tried that but it still didn't work. Have add the output section to the end of my question. Don't know if it will help. –  Apr 13 '15 at 15:34
  • You have a different error message now... an `IllegalArgumentException`, not a `NullPointerException`. It is now actually trying to load the FXML file `AccountingSnapshots_1.fxml`, but you have an unrelated error in that FXML file and its corresponding controller (you apparently have defined a `MenuButton` in the FXML file (line 16), but you are injecting it into a `MenuItem` field in the controller). – James_D Apr 13 '15 at 15:41
  • Clearly finding the AccountingSnapshots_1.fxml file. I have corrected the MenuButton to MenuItem. Now the build is successful but doesn't load the file. I have edited the answer to add the output result. –  Apr 13 '15 at 16:13
  • 1
    Impossible to diagnose from there. It looks like it is running with no errors. I recommend you create a [simple, complete example that others can run](http://stackoverflow.com/help/mcve) and post it - probably in a new question since the original issue here ("cannot find symbol") is actually resolved. (You may find the process of creating the simple example leads you to discover the solution anyway.) – James_D Apr 13 '15 at 16:18
  • James, thanks for your help and suggestion. I will spend a day or two going back and producing another question. –  Apr 13 '15 at 16:24
0

This is an old thread, but the answer given was spot on

Here's a bit of code for anyone that's facing the same issues

Normally, I would just pass in a node to the stage object, but as has already been stated - a menu/menuItem cannot be converted to a node. Using the fx:id of the outermost node solves the problem. reportAnchorpane is the name of the (root) node for this respective 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();
}

On the 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>
Silkmane
  • 1
  • 2