2013-12-15 25 views
6

我想基於menuItem點擊更改javafx階段中的場景。這裏是我的sample.fxml:無法從JavaFX中的MenuItem獲取場景

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

那麼,如何從菜單項中點擊事件處理程序獲取包含舞臺/場景?

EDIT

Node node= (Node)event.getSource(); 
在controller.java

是行號29,其是給的問題。

+0

*'java.lang.NullPointerException at sample.Controller.onTweetsMenuActionPerformed(Controller.java:30)'* =>其中是Controller.java類的第30行? – assylias

+0

@assylias Stage stage =(Stage)node.getScene()。getWindow(); – rahulserver

+0

我的猜測是'node'不可見,因此沒有Window。您可以嘗試調試代碼以檢查當時的變量。 – assylias

回答

12

顯示在第二你真正的錯誤堆棧跟蹤的最後一行:

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 Docs,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

我建議抓住源作爲一個對象,然後在繼續之前檢查它的類型。另外,我使用getSource()方法遇到了問題; getTarget()方法對我更好。無論哪種方式,您仍然需要一種方法來進入舞臺。

爲此,您可能需要在FXML中使用fx:id標籤,而不是id標籤。這將允許您將FXML元素直接注入到控制器中。例如,您可以通過將MenuBar元素注入控制器來從MenuBar(它是Node的子類)中獲取舞臺。

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

你可能需要做一些調整在這裏,但我希望它幫助。

+0

聽起來不錯。 +10爲你。但是在嘗試之後,wuld確認它是答案。 – rahulserver

-1

這是一種基於菜單項被點擊的方式獲得SceneWindow的方法,而不是作爲注入的FXML元素,或者如果您使用FXML創建它,則無需引用它。換句話說,通過使用Event的目標。

在我的問題,我有一個MenuButton用下拉菜單(一ContextMenu,我發現了,我不知道,因爲我創造了我的菜單中FXML)含MenuItems,我想開一個FileChooser,這就需要當點擊「保存」MenuItem時,作爲參數的Window

通常情況下,我會沿着獲取事件目標的路線,然後是父項,然後是下一個父項等,最後是場景,然後是窗口。作爲MenuMenuItemNode S和因此沒有Parent■在這種情況下,但是我做了以下內容:

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,因此爲什麼我沒有意識到我必須通過調用來獲取ContextMenugetParentPopup()沒有一些試用和錯誤:

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

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

+2

請給你的答案添加一個解釋 –