JavaFX用fxml打开新窗口问题

问题描述:

我正在开发密码管理器程序。在此程序中打开新窗口时,会在addEntry()鼠标单击事件中引发异常。我有一个Main类打开主窗口(与sample.fxml)和Controller类,设法打开新窗口(与addNewEntryDialog.fxml)。这里是我的代码:JavaFX用fxml打开新窗口问题

Main.java

package sample; 

import javafx.application.Application; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.stage.Modality; 
import javafx.stage.Stage; 

import java.io.IOException; 

public class Main extends Application { 

    @Override 
    public void start(Stage primaryStage) throws Exception{ 
     Parent root = FXMLLoader.load(getClass().getResource("/sample.fxml")); 
     primaryStage.setTitle("Password Manager"); 
     primaryStage.setScene(new Scene(root, 800, 600)); 
     primaryStage.show(); 
    } 

    public static void main(String[] args) { 
     launch(args); 
    } 
} 

Controller.java

package sample; 

import javafx.collections.FXCollections; 
import javafx.collections.ObservableList; 
import javafx.fxml.FXML; 
import javafx.fxml.FXMLLoader; 
import javafx.fxml.Initializable; 
import javafx.scene.Parent; 
import javafx.scene.Scene; 
import javafx.scene.control.*; 
import javafx.scene.control.cell.PropertyValueFactory; 
import javafx.stage.Stage; 
import javafx.stage.StageStyle; 

import java.io.IOException; 
import java.net.URL; 
import java.sql.*; 
import java.util.ResourceBundle; 

public class Controller implements Initializable { 
    public ObservableList<Data> data; 
    public TableView dbTable; 
    public TableColumn siteColumn, usernameColumn, passwordColumn; 

    public ToggleButton showPasswordToggle; 


    @Override 
    public void initialize(URL location, ResourceBundle resources) { 
     fillTable(); 
    } 

    public void fillTable(){ 
     data = FXCollections.observableArrayList(); 
     String query = "SELECT * FROM accounts"; 

     try { 
      Connection connection = connectToDatabase(); 
      ResultSet resultSet = connection.createStatement().executeQuery(query); 

      while (resultSet.next()) { 
       data.add(new Data(resultSet.getString(1), resultSet.getString(2), resultSet.getString(3))); 
      } 

      siteColumn.setCellValueFactory(new PropertyValueFactory("site")); 
      usernameColumn.setCellValueFactory(new PropertyValueFactory("username")); 
      passwordColumn.setCellValueFactory(new PropertyValueFactory("password")); 

      dbTable.setItems(data); 
     } catch (SQLException e) { 
      e.printStackTrace(); 
     } 
    } 

    @FXML 
    public void addEntry() throws IOException { 
     Stage stage = new Stage(); 
     Parent root = FXMLLoader.load(getClass().getResource("/addEntryDialog.fxml")); 
     stage.setTitle("Add new entry"); 
     stage.setScene(new Scene(root, 800, 600)); 
     stage.show(); 
    } 

addEntryDialog.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.*?> 
<?import javafx.scene.control.*?> 
<?import java.lang.*?> 
<?import javafx.scene.layout.*?> 

<Pane maxHeight="-Infinity" maxWidth="-Infinity" minHeight="-Infinity" minWidth="-Infinity" prefHeight="200.0" prefWidth="400.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller"> 
    <children> 
     <GridPane layoutX="28.0" layoutY="21.0" prefHeight="123.0" prefWidth="317.0"> 
     <columnConstraints> 
      <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> 
      <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> 
     </columnConstraints> 
     <rowConstraints> 
      <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> 
      <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> 
      <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> 
     </rowConstraints> 
     <children> 
      <Label layoutX="33.0" layoutY="26.0" text="Site:" /> 
      <Label layoutX="28.0" layoutY="78.0" text="Username:" GridPane.rowIndex="1" /> 
      <Label layoutX="44.0" layoutY="135.0" text="Password:" GridPane.rowIndex="2" /> 
      <TextField fx:id="siteField" layoutX="150.0" layoutY="21.0" GridPane.columnIndex="1" /> 
      <TextField fx:id="usernameField" layoutX="150.0" layoutY="73.0" GridPane.columnIndex="1" GridPane.rowIndex="1" /> 
      <PasswordField fx:id="passwordField" layoutX="150.0" layoutY="123.0" GridPane.columnIndex="1" GridPane.rowIndex="2" /> 
     </children> 
     </GridPane> 
     <Button layoutX="327.0" layoutY="163.0" mnemonicParsing="false" text="OK" /> 
     <Button layoutX="246.0" layoutY="163.0" mnemonicParsing="false" text="Cancel" /> 
    </children> 
</Pane> 

sample.fxml

<?xml version="1.0" encoding="UTF-8"?> 

<?import javafx.scene.control.*?> 
<?import java.lang.*?> 
<?import javafx.scene.layout.*?> 
<?import javafx.geometry.Insets?> 
<?import javafx.scene.layout.GridPane?> 
<?import javafx.scene.control.Button?> 
<?import javafx.scene.control.Label?> 

<Pane prefHeight="600.0" prefWidth="800.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="sample.Controller"> 
    <children> 
     <TableView fx:id="dbTable" layoutX="4.0" layoutY="85.0" prefHeight="505.0" prefWidth="790.0"> 
     <columns> 
      <TableColumn fx:id="siteColumn" prefWidth="263.0" text="Site" /> 
      <TableColumn fx:id="usernameColumn" prefWidth="263.0" text="Username" /> 
      <TableColumn fx:id="passwordColumn" prefWidth="263.0" text="Password" /> 
     </columns> 
     </TableView> 
     <GridPane layoutX="14.0" layoutY="27.0" prefHeight="25.0" prefWidth="263.0"> 
     <columnConstraints> 
      <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> 
      <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> 
      <ColumnConstraints hgrow="SOMETIMES" minWidth="10.0" /> 
     </columnConstraints> 
     <rowConstraints> 
      <RowConstraints minHeight="10.0" vgrow="SOMETIMES" /> 
     </rowConstraints> 
     <children> 
      <Button fx:id="addNewEntry" layoutX="14.0" layoutY="14.0" mnemonicParsing="false" onMouseClicked="#addEntry" text="Add.." GridPane.columnIndex="0" /> 
      <Button fx:id="removeEntry" layoutX="83.0" layoutY="14.0" mnemonicParsing="false" text="Remove.." GridPane.columnIndex="1" /> 
      <Button fx:id="editEntry" layoutX="178.0" layoutY="14.0" mnemonicParsing="false" text="Edit.." GridPane.columnIndex="2" /> 
     </children> 
     </GridPane> 
     <ToggleButton fx:id="showPasswordToggle" layoutX="671.0" layoutY="27.0" mnemonicParsing="false" text="Show Password" /> 
    </children> 
</Pane> 

堆栈跟踪

Exception in thread "JavaFX Application Thread" java.lang.RuntimeException: java.lang.reflect.InvocationTargetException 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1774) 
    at javafx.fxml.FXMLLoader$ControllerMethodEventHandler.handle(FXMLLoader.java:1657) 
    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.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.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$ClickGenerator.postProcess(Scene.java:3470) 
    at javafx.scene.Scene$ClickGenerator.access$8100(Scene.java:3398) 
    at javafx.scene.Scene$MouseHandler.process(Scene.java:3766) 
    at javafx.scene.Scene$MouseHandler.access$1500(Scene.java:3485) 
    at javafx.scene.Scene.impl_processMouseEvent(Scene.java:1762) 
    at javafx.scene.Scene$ScenePeerListener.mouseEvent(Scene.java:2494) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:352) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:275) 
    at java.security.AccessController.doPrivileged(Native Method) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$354(GlassViewEventHandler.java:388) 
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389) 
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:387) 
    at com.sun.glass.ui.View.handleMouseEvent(View.java:555) 
    at com.sun.glass.ui.View.notifyMouse(View.java:937) 
    at com.sun.glass.ui.gtk.GtkApplication._runLoop(Native Method) 
    at com.sun.glass.ui.gtk.GtkApplication.lambda$null$49(GtkApplication.java:139) 
    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:498) 
    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:498) 
    at sun.reflect.misc.MethodUtil.invoke(MethodUtil.java:275) 
    at javafx.fxml.FXMLLoader$MethodHandler.invoke(FXMLLoader.java:1771) 
    ... 31 more 
Caused by: javafx.fxml.LoadException: 
/home/umberto/passwordManager/out/production/passwordManager/addEntryDialog.fxml 

    at javafx.fxml.FXMLLoader.constructLoadException(FXMLLoader.java:2601) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2579) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2441) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3214) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3175) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3148) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3124) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:3104) 
    at javafx.fxml.FXMLLoader.load(FXMLLoader.java:3097) 
    at sample.Controller.addEntry(Controller.java:58) 
    ... 41 more 
Caused by: java.lang.NullPointerException 
    at sample.Controller.loadTableData(Controller.java:45) 
    at sample.Controller.initialize(Controller.java:30) 
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548) 
    ... 49 more 
+1

那么问题是什么? –

+0

它调用addEntry()方法(鼠标点击事件) –

+2

时会产生很多异常错误,因此请将堆栈跟踪添加到您的问题中。 –

看看你addEntryDialog.fxml文件。这个视图的控制器的定义如下:

<Pane ... fx:controller="sample.Controller> 

JavaFX加载视图,查找控制器并创建它。 (此时另一个sample.Controller对象被实例化)。创建后看到该控制器实现了Initializable接口,因此它执行initialize方法,该方法又调用fillTable方法,最后到达语句siteColumn.setCellValueFactory(..)。问题是没有siteColumn对于addEntryDialog.fxml视图 - 它没有绑定,因为在该视图上没有该id。

解决方案是为addEntryView.fxml创建适当的控制器,并在xml fx:controller属性中调用它。

+0

我只需要addEntryView.fxml点击“添加”按钮添加一个新的表条目,siteColumn是表的一部分。所以我只需要从一个方法打开一个新窗口,我不关心表列。 –

+0

@UmbertoPalazzini没错,但是您已将'sample.Controller'定义为'addEntryView'对话框的控制器。这就是为什么它会抛出空指针异常。创建新窗口涉及为其创建控制器,控制器被创建并在初始化期间抛出NPE,因为'addEntryView'上没有列。 –