我一直在构建电影院预订应用程序,并试图创建一个显示电影和放映时间的场景。当我使用锚窗格和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'注入到FXML加载器中,也无法从getRoot()方法访问它。
答案 0 :(得分:1)
这样做的原因是ScrollPane
添加了内容ScrollBar
等。在创建皮肤时,在第一次布局传递过程中将其移到场景上。此布局过程在JavaFX应用程序线程“重新控制”之后发生(即,您已经完成了事件处理程序,Application.start
方法或让JavaFX执行代码的类似方式)。
请注意,您正在以非常奇怪的方式使用控制器类。我建议使用此问题答案中描述的方法之一与控制器进行通信:Passing Parameters 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
对象,因此可以通过从a进行初始化来简化代码。
@FXML
private void initialize()
控制器中的方法,并从控制器代码中删除每个与MovieShowings
相关的部分。这样,您就不必将其传递给控制器了。
使用ListView
使用自定义单元格也可以显示电影...