有 Java 编程相关的问题?

你可以在下面搜索框中键入要查询的问题!

java初始化方法在主类中的指定方法之前运行

我试图将一个对象从一个控制器传递到另一个控制器。我传递给BookViewController的rowData对象对于initialize方法的工作至关重要,如果没有设置数据,就会出现NullPointerException,这在我的例子中确实发生了

似乎initialize方法在setRowData方法之前运行。正如我所说,initialize方法依赖于setRowData方法的执行

我错过了什么

梅因。爪哇

public class Main extends Application {

    private static Stage primaryStage;
    private static BorderPane mainLayout;

    @Override
    public void start(Stage primaryStage) throws Exception {
        Main.primaryStage = primaryStage;
        Main.primaryStage.setTitle("BookingApp");
        showMainView();
    }

    private void showMainView() throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("MainView.fxml"));
        mainLayout = loader.load();
        Scene scene = new Scene(mainLayout);
        primaryStage.setScene(scene);
        primaryStage.show();
    }

    public static void showBookView(Trip rowData) throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("BookView.fxml"));
        BorderPane bookTrip = loader.load();

        BookViewController bvc = loader.getController();
        // The below method never runs.. why?
        bvc.setRowData(rowData);       

        Stage bookStage = new Stage();                
        bookStage.setTitle("BookingApp");
        bookStage.initModality(Modality.WINDOW_MODAL);
        bookStage.initOwner(primaryStage);
        Scene scene = new Scene(bookTrip);
        bookStage.setScene(scene);
        bookStage.showAndWait();
    }

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

BookViewController。爪哇

public class BookViewController implements Initializable {

    private String dbUrl = "jdbc:postgresql://localhost:5432/BookingApp";

    private String dbUsername = "postgres";

    private String dbPassword = "secret";

    @FXML
    private TextField personnr;

    @FXML
    private TextField name;

    @FXML
    private TextField email;

    @FXML
    private TextField telnr;

    @FXML
    private Button addTraveler;

    @FXML
    private Button removeTraveler;

    @FXML
    private TableView<Traveler> travelers;

    @FXML
    private TableColumn<?, ?> personnrColumn;

    @FXML
    private TableColumn<?, ?> nameColumn;

    @FXML
    private TableColumn<?, ?> emailColumn;

    @FXML
    private TableColumn<?, ?> telnrColumn;

    @FXML
    private TableView<Trip> trips;

    @FXML
    private TableColumn<?, ?> originColumn;

    @FXML
    private TableColumn<?, ?> destinationColumn;

    @FXML
    private TableColumn<?, ?> departureColumn;

    @FXML
    private TableColumn<?, ?> arrivalColumn;

    @FXML
    private TableColumn<?, ?> driverColumn;

    @FXML
    private TableColumn<?, ?> priceAmountColumn;

    @FXML
    private TableColumn<?, ?> seatsColumn;

    @FXML
    private Button bookTrip;

    private Trip rowData;

    private ObservableList<Trip> tripData;

    public void setRowData(Trip rowData) {
        this.rowData = rowData;
        // The below println is never printed to the console..
        System.out.println("Test");
    }

    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        addTraveler.setDisable(true);
        removeTraveler.setDisable(true);
        populateTravelPlan();
    }

    @FXML
    private void populateTravelPlan() {
        try {
            Connection conn = DriverManager.getConnection(dbUrl, dbUsername, dbPassword);
            tripData = FXCollections.observableArrayList();
            ResultSet rs = null;
            System.out.println(rowData.getTrip1()); // Here it breaks
            System.out.println(rowData.getTrip2());
            System.out.println(rowData.getTrip3());
            if(rowData.getTrip1() != 0 && rowData.getTrip2() == 0 && rowData.getTrip3() == 0) {
                rs = conn.createStatement().executeQuery(
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip1() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "order by departure;");
            } else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() == 0) {
                rs = conn.createStatement().executeQuery(
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip1() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "union\r\n" + 
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip2() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "order by departure;");
            } else if(rowData.getTrip1() != 0 && rowData.getTrip2() != 0 && rowData.getTrip3() != 0) {
                rs = conn.createStatement().executeQuery(
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip1() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "union\r\n" + 
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip2() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "union\r\n" + 
                        "select trip.tripid, connexion.origin, connexion.destination, trip.departure, trip.arrival, trip.driverpnr, trip.priceamount, trip.seats\r\n" + 
                        "from trip, connexion\r\n" + 
                        "where trip.tripid = " + rowData.getTrip3() + "\r\n" + 
                        "and trip.connexionid = connexion.connexionid\r\n" + 
                        "order by departure;");
            }
            tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8)));
            while(rs.next()) {
                tripData.add(new Trip(rs.getInt(1), rs.getString(2), rs.getString(3), ""+rs.getTimestamp(4), ""+rs.getTimestamp(5), rs.getString(6), ""+rs.getInt(7), ""+rs.getInt(8)));
            }
        } catch (SQLException e) {
            e.printStackTrace();
        }
        trips.setItems(tripData);
    }
} 

例外

javafx.fxml.LoadException: 
/C:/Users/David/Desktop/eclipse/BookingApp1/bin/booking/BookView.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.load(FXMLLoader.java:2409)
    at booking.Main.showBookView(Main.java:35)
    at booking.MainViewController$1.handle(MainViewController.java:227)
    at booking.MainViewController$1.handle(MainViewController.java:1)
    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.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:381)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler$MouseEventNotification.run(GlassViewEventHandler.java:295)
    at java.security.AccessController.doPrivileged(Native Method)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.lambda$handleMouseEvent$353(GlassViewEventHandler.java:417)
    at com.sun.javafx.tk.quantum.QuantumToolkit.runWithoutRenderLock(QuantumToolkit.java:389)
    at com.sun.javafx.tk.quantum.GlassViewEventHandler.handleMouseEvent(GlassViewEventHandler.java:416)
    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.win.WinApplication._runLoop(Native Method)
    at com.sun.glass.ui.win.WinApplication.lambda$null$147(WinApplication.java:177)
    at java.lang.Thread.run(Unknown Source)
Caused by: java.lang.NullPointerException
    at booking.BookViewController.populateTravelPlan(BookViewController.java:109)
    at booking.BookViewController.initialize(BookViewController.java:100)
    at javafx.fxml.FXMLLoader.loadImpl(FXMLLoader.java:2548)
    ... 39 more 

共 (1) 个答案

  1. # 1 楼答案

    It seems that the initialize-method runs BEFORE the setRowData-method.

    这的确是正确的。initialize()方法由FXMLLoader调用,作为load()执行的一部分,这必然发生在您有机会调用setRowData(...)之前

    What am I missing out on here?

    没什么,真的

    有几个可能的解决办法。一种是简单地避免initialize()方法依赖于传递给setRowData()的数据,并将任何依赖于这些数据的代码移动到后一种方法。在这种情况下,这是非常微不足道的:

    public void setRowData(Trip rowData) {
        this.rowData = rowData;
        populateTravelPlan();
    }
    
    @Override
    public void initialize(URL arg0, ResourceBundle arg1) {
        addTraveler.setDisable(true);
        removeTraveler.setDisable(true);
        // don't do this here:
        // populateTravelPlan();
    }
    

    如果您不喜欢该解决方案,另一个选项是在代码中而不是在FXML中设置控制器。简单地说,您可以从FXML文件中删除fx:controller属性,然后在加载FXML时,创建一个控制器实例,调用setRowData()(或者通过构造函数初始化行数据),然后在FXMLLoader上调用setController()。这个解决方案在Passing Parameters JavaFX FXML中有详细描述

    该解决方案的一个缺点是,如果在FXML设计中使用Scene Builder,Scene Builder将失去一些功能(因为它不再知道用于创建控制器的类)。如果您想保留该功能,可以使用控制器工厂

    对于该解决方案,我将修改控制器,以便将行数据传递给构造函数:

    public class BookViewController implements Initializable {
    
        // @FXML-annotated fields omitted...
    
        private final Trip rowData;
    
        public BookViewController(Trip rowData) {
            this.rowData = rowData ;
        }
    
        // remove this, it is now initialized in the constructor
        // public void setRowData(Trip rowData) {
        //     this.rowData = rowData;
        //     // The below println is never printed to the console..
        //     System.out.println("Test");
        // }
    
        @Override
        public void initialize(URL arg0, ResourceBundle arg1) {
            addTraveler.setDisable(true);
            removeTraveler.setDisable(true);
            populateTravelPlan();
        }
    
        // etc...
    }
    

    此构造函数将阻止FXMLLoader使用其默认方法创建控制器实例,因此向加载程序提供控制器工厂以覆盖控制器的创建方式:

    public static void showBookView(Trip rowData) throws IOException {
        FXMLLoader loader = new FXMLLoader();
        loader.setLocation(Main.class.getResource("BookView.fxml"));
        loader.setControllerFactory(type -> {
            if (type == BookViewController.class) {
                return new BookViewController(rowData);
            }
            // default behavior: need this in case there are <fx:include> in the FXML
            try {
                return type.getConstructor().newInstance();
            } catch (Exception exc) {
                // fatal...
                throw new RuntimeException(exc);
            }
        });
        BorderPane bookTrip = loader.load();
    
        Stage bookStage = new Stage();                
        bookStage.setTitle("BookingApp");
        bookStage.initModality(Modality.WINDOW_MODAL);
        bookStage.initOwner(primaryStage);
        Scene scene = new Scene(bookTrip);
        bookStage.setScene(scene);
        bookStage.showAndWait();
    }