2013-12-15 5 views
6

Sto cercando di cambiare la scena in uno stage javafx basato su menuItem. Qui è la mia sample.fxml:Impossibile richiamare Scene da MenuItem in JavaFX

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

Ecco il mio 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. 
    } 
} 

Ecco la mia 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); 
    } 
} 

Quando clicco sul menuItem Gestisci sotto Menu Account, ottengo la seguente eccezione:

"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 

Quindi, come posso ottenere lo stage/scena che contiene dal gestore di eventi selezionato per il menu Item?

EDIT La linea

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

in controller.java è la linea numero 29 che è dando problemi.

+0

* 'java.lang.NullPointerException su sample.Controller.onTweetsMenuActionPerformed (Controller.java:30)' * => dove si trova la riga 30 della classe Controller.java? – assylias

+0

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

+0

La mia ipotesi è che 'node' non è visibile quindi non ha una finestra. Potresti provare a eseguire il debug del codice per verificare le variabili in quel punto. – assylias

risposta

12

Il vostro vero errore è mostrato nella penultima riga della traccia dello stack:

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

Questo errore si riferisce la riga seguente dal vostro controller:

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

Guardando il JavaFX Documenti API, né MenuItem né Menu sono sottoclassi di Nodo. http://docs.oracle.com/javafx/2/api/javafx/scene/control/MenuItem.html http://docs.oracle.com/javafx/2/api/javafx/scene/control/Menu.html

Suggerirei di afferrare il sorgente come oggetto, quindi controllarne il tipo prima di continuare. Inoltre, mi sono imbattuto in problemi usando il metodo getSource(); il metodo getTarget() ha funzionato meglio per me. In ogni caso, hai ancora bisogno di un modo per arrivare allo Stage.

Per fare ciò, è possibile utilizzare il tag fx:id nel proprio FXML anziché il tag id. Questo ti permetterà di iniettare gli elementi FXML direttamente nel tuo controller. Ad esempio, puoi prendere lo Stage dal MenuBar (che è una sottoclasse di Nodo) iniettando l'elemento MenuBar nel tuo controller.

Nella FXML:

<MenuBar fx:id="myMenuBar" layoutY="0.0" maxWidth="1.7976931348623157E308" prefWidth="300.0" useSystemMenuBar="false" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="2.0"> 

Nel controllore:

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

Potrebbe essere necessario fare un po 'di tweaking qui, ma spero che aiuta.

+0

Suona alla grande. +10 per voi Ma lo confermeremmo come la risposta dopo aver provato. – rahulserver

-1

Ecco un modo per ottenere Scene e Window in base a una voce di menu che viene fatta clic senza che sia un elemento FXML iniettato o senza fare riferimento se lo si è creato con FXML. In altre parole, utilizzando la destinazione di Event.

Nel mio problema che ho avuto un MenuButton con un menu a discesa (un ContextMenu come ho scoperto, che non sapevo come avevo creato il mio menu in FXML) contenente MenuItems e volevo aprire una FileChooser, che ha bisogno di il Window come argomento, quando è stato fatto clic su "Salva" MenuItem.

Normalmente avrei seguito il percorso per ottenere l'obiettivo dell'evento, quindi il genitore, quindi il prossimo genitore ecc. E infine la scena e quindi la finestra. Come Menu e MenuItem non sono Node s e, pertanto, non hanno Parent s In questo caso però ho fatto la seguente:

FileChooser fileChooser = new FileChooser(); 

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

fileChooser.showSaveDialog(window); 

Oppure, convertendo la maggior parte in una sola riga argomento:

FileChooser fileChooser = new FileChooser(); 

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

Proprio adattalo come necessario in base al tuo grafico di scena (cioè quanti genitori hai bisogno di passare in caso di sottomenu, ecc.) e cosa vuoi fare una volta che hai lo Window, ma una volta arrivato allo ContextMenu (la lista popup di MenuItems), è possibile ottenere il Scene e quindi da quello ottenere il Window.




Per inciso, qui è la FXML ho usato per creare il mio MenuButton, e quindi, perché non mi rendevo conto che dovevo ottenere il ContextMenu tramite una chiamata al getParentPopup() senza qualche prova . ed errore:

<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

palcoscenico = (stage) ((Node) myMenuBar) .getScene() getWindow();

+2

per favore aggiungi una spiegazione alla tua risposta –