簡體   English   中英

使用滾動窗格javafX時出現空指針異常

[英]Null Pointer Exception when using Scroll pane javafX

我一直在構建電影院預訂應用程序,並試圖創建一個顯示電影和顯示時間的場景。 當我使用錨定窗格和vbox顯示所有信息時,它可以工作,但是當我嘗試插入另一個滾動窗格(在SceneBuilder中)時,FXML加載程序返回空指針異常,我無法弄清原因...

這是我的FXML代碼

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

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

<AnchorPane prefHeight="598.0" prefWidth="798.0" xmlns="http://javafx.com/javafx/8" xmlns:fx="http://javafx.com/fxml/1" fx:controller="MovieShowingsController">
   <children>
      <MenuBar>
        <menus>
          <Menu mnemonicParsing="false" text="myBookings">
            <items>
              <MenuItem mnemonicParsing="false" text="Close" />
            </items>
          </Menu>
        </menus>
      </MenuBar>
      <ScrollPane fx:id="scrollpane" hbarPolicy="NEVER" layoutY="22.0" prefHeight="576.0" prefWidth="798.0" AnchorPane.bottomAnchor="0.0" AnchorPane.leftAnchor="0.0" AnchorPane.rightAnchor="0.0" AnchorPane.topAnchor="22.0">
         <content>
            <VBox fx:id="vbox" prefHeight="555.0" prefWidth="740.0" />
         </content>
      </ScrollPane>
   </children>
</AnchorPane>

這是控制器類

public class MovieShowingsController {

    @FXML
    private VBox vbox;

    private ArrayList<FilmInfo> filmList;

    private ArrayList<Screening> screeningList;

    private MovieShowings showings;

    //FXML loader instance variable to be accessed by dynamic scene controller
    private VBox holder;

    @FXML
    private void initialize() {
    }

    public MovieShowingsController() {

    }

    public MovieShowingsController(MovieShowings showings) {

        String date = "2019-04-15";
        Date sqlDate = Date.valueOf(date);

         System.out.println("\n");
         System.out.println("***Screenings for " + date + "***");

         filmList = new ArrayList();
         screeningList = DatabaseConnection.getInstance().retrieveScreeningsForDay(sqlDate);

         for (Screening screeningInstance : screeningList) {

             if (!filmList.contains(screeningInstance.getFilmInfo())) {

                 filmList.add(screeningInstance.getFilmInfo());

             }

             System.out.println(screeningInstance.toString());
          }

        Collections.sort(screeningList);

        this.showings = showings;

        //populating FXML instance variable from loader
        this.holder = (VBox) showings.getRoot().lookup("#vbox");

        buildMovieShowings(holder);
    }

    private void buildMovieShowings(VBox holder) {

        holder.setSpacing(50);

        for (int i = 0; i < filmList.size(); i++) {

            VBox infoHolder = new VBox();

            infoHolder.setSpacing(10);

            Label title = new Label(String.format("%s%8s", filmList.get(i).getTitle(),
                    "(" + filmList.get(i).getRating() + ")"));

            title.setStyle("-fx-font: 24 arial;");

            Label duration = new Label(String.format("%s%s%s", "Film Length: ",
                    filmList.get(i).getDuration(), " mins"));

            duration.setStyle("-fx-font: 24 arial;");

            Label director = new Label(String.format("%s%s", "Directed By: ",
                    filmList.get(i).getDirector()));

            director.setStyle("-fx-font: 24 arial;");

            infoHolder.getChildren().addAll(title, duration, director);

            HBox timesHolder = new HBox();

            timesHolder.setSpacing(10);

            for (int j = 0; j < screeningList.size(); j++) {

                if (screeningList.get(j).getFilmInfo().equals(filmList.get(i))){

                    Label time = new Label();

                    Background black = new Background(new BackgroundFill(Color.BLACK, CornerRadii.EMPTY, Insets.EMPTY));

                    Background red = new Background(new BackgroundFill(Color.RED, CornerRadii.EMPTY, Insets.EMPTY));

                    time.setBackground(black);

                    Screen screen = screeningList.get(j).getScreen();
                    Screening screening = screeningList.get(j);

                    time.setOnMouseClicked(new EventHandler<MouseEvent>() {

                    @Override
                    public void handle(MouseEvent e) {

                        try {

                        System.out.println(screening.getFilmInfo().getTitle() + screening.getShowTime());

                        time.setBackground(red);

                        SeatMap seatMap = new SeatMap();

                        SeatMapController seatMapController = new SeatMapController(seatMap, 
                                screen);

                        Scene seatMapScene = seatMap.getScene();

                        Stage window = (Stage) ((Node) e.getSource()).getScene().getWindow();

                        window.setResizable(false);

                        window.setWidth(800);
                        window.setHeight(600);

                        window.setScene(seatMapScene);

                        window.show();

                        }

                        catch (IOException ex) {

                            ex.printStackTrace();

                            }

                        }

                    });

                    time.setPrefSize(100, 100);

                    time.setAlignment(Pos.CENTER);

                    time.setStyle("-fx-border-color: black");

                    time.setStyle("-fx-font: 22 arial;");

                    time.setStyle("-fx-text-fill: white");

                    time.setText(screeningList.get(j).getShowTime());

                    timesHolder.getChildren().add(time);
                }
            }

            infoHolder.getChildren().add(timesHolder);

            holder.getChildren().add(infoHolder);
        }
    }
}

主班

public class MovieShowings{

    private AnchorPane root;

    public MovieShowings() {

        try {

            root = FXMLLoader.load(getClass().getResource("movieshowings.fxml"));
        }

        catch(IOException e){

            e.printStackTrace();
        }

    }


    public Scene getScene() {

    Scene scene = new Scene(root,800,600);

    return scene;

    }

    public AnchorPane getRoot() {

        return root;
    }

}

以及用戶登錄后調用它的代碼

if(DatabaseConnection.getInstance().login(Username.getText(), Password.getText())) {

            MovieShowings films = new MovieShowings();

            MovieShowingsController filmsController = new MovieShowingsController(films);

            Scene movieShowings = films.getScene();

            Stage window = (Stage) ((Node) e.getSource()).getScene().getWindow();

            window.setScene(movieShowings);

            window.show();

關於如何解決此問題的任何想法?

編輯:fx:id'vbox'不能從getRoot()方法訪問,即使已被注入FXML加載器中

原因是ScrollPane添加了ScrollBar內容。 在創建皮膚時,在第一次布局傳遞過程中將其移至場景。 在JavaFX應用程序線程“重新控制”之后發生此布局過程(即,您已經完成了事件處理程序, Application.start方法或使JavaFX執行代碼的類似方式)。

請注意,您正在以非常奇怪的方式使用控制器類。 我建議使用此問題的答案中描述的方法之一與控制器進行通信: 傳遞參數JavaFX FXML

例如:

public class MovieShowings{

    private AnchorPane root;

    public MovieShowings() {

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("movieshowings.fxml"));
            root = loader.load();
            MovieShowingsController controller = loader.getController();
            controller.initMovieShowings(this);
        }

        catch(IOException e){

            e.printStackTrace();
        }

    }
    ...

}
public class MovieShowingsController {

    ...

    public void initMovieShowings(MovieShowings showings) {
        String date = "2019-04-15";
        Date sqlDate = Date.valueOf(date);

         System.out.println("\n");
         System.out.println("***Screenings for " + date + "***");

         filmList = new ArrayList();
         screeningList = DatabaseConnection.getInstance().retrieveScreeningsForDay(sqlDate);

         for (Screening screeningInstance : screeningList) {

             if (!filmList.contains(screeningInstance.getFilmInfo())) {

                 filmList.add(screeningInstance.getFilmInfo());

             }

             System.out.println(screeningInstance.toString());
          }

        Collections.sort(screeningList);

        this.showings = showings;

        //populating FXML instance variable from loader

        // use the injected field here
        buildMovieShowings(vbox);
    }

    ...
}

由於您實際上MovieShowings在控制器中使用MovieShowings對象,因此可以通過從

@FXML
private void initialize()

控制器中的方法,並從控制器代碼中刪除每個與MovieShowings相關的部分。 這樣,您就不必將其傳遞給控制器​​了。

使用自定義單元格使用ListView也可以是顯示電影的選項...

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM