Why getTableRow().getItem() is returning a null reference, even on not empty rows?

Viewed 420

So I created this little App with a search bar and a table view. When the screen initializes, I use tableView.setItems() to add a fixed list of items to my table. Later, when the user performs a query, a filtered list is generated and I call tableView.setItems() again. When the list is being rendered, my code calls methods against getRowTable().getItem() to add behaviour to a button in each row. Everything is rendered correctly, however, it seems that updateItem() is being called more times than it should, and getRowTable().getItem() returns a null reference making the program throw an exception.

What is causing this? Code below.

App.java

public class App extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {
        URL url = getClass().getResource("/com/lib/fxml/search-movies.fxml");

        try {
            Parent root = FXMLLoader.load(url);
            Scene scene = new Scene(root, 1024, 768);
            primaryStage.setScene(scene);
            primaryStage.show();
        } catch (IOException exception) {
            exception.printStackTrace();
        }
    }


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

SearchMovies.java

public class SearchMovies {
    @FXML TextField searchField;
    @FXML TableView<Movie> tableView;
    @FXML TableColumn<Movie, String> titleColumn;
    @FXML TableColumn<Movie, String> directorColumn;
    @FXML TableColumn<Movie, Void> likeColumn;

    private ArrayList<Movie> movieList = new ArrayList<>(Arrays.asList(
        new Movie("Persona", "Ingmar Bergman"),
        new Movie("City of God", "Fernando Meirelles"),
        new Movie("Pulp Fiction", "Quentin Tarantino"),
        new Movie("Gone Girl", "David Fincher"),
        new Movie("Fight Club", "David Fincher"),
        new Movie("Perfect Blue", "Satoshi Kon"),
        new Movie("Prisoners", "Denis Villeneuve"),
        new Movie("Sin City", "Frank Miller"),
        new Movie("Mean Girls", "Mark Waters"),
        new Movie("Breakfast Club", "John Hughes"),
        new Movie("Sixteen Candles", "John Hughes"),
        new Movie("Reservoir Dogs", "Quentin Tarantino")
    ));

    private ObservableList<Movie> observableMovieList = FXCollections.observableArrayList(movieList);

    @FXML
    public void initialize() {
        titleColumn.setCellValueFactory(item -> item.getValue().titleProperty());
        directorColumn.setCellValueFactory(item -> item.getValue().directorProperty());

        likeColumn.setCellFactory(col -> new TableCell<Movie, Void>() {
            private final Button button = new Button("LIKE");

            @Override
            public void updateItem(Void item, boolean empty) {
                super.updateItem(item, empty);

                if (empty) {
                    setGraphic(null);
                } else {
                    Movie movie = getTableRow().getItem();
                    button.setOnAction(e -> System.out.println("Someone liked " + movie.getTitle() + " " + movie.getDirector()));
                    System.out.println("Rendering row for " + movie.getTitle() + " by " + movie.getDirector());
                    setGraphic(button);
                }
            }
        });

        tableView.setItems(observableMovieList);
    }

    @FXML
    public void search() {
        String query = searchField.getText();

        if (query == null || query.isBlank() || query.isEmpty()) {
            return;
        }

        observableMovieList = FXCollections.observableArrayList(filterMovies(query));
        tableView.setItems(observableMovieList);
    }

    private ArrayList<Movie> filterMovies(String query) {
        ArrayList<Movie> filteredMovies = new ArrayList<>();

        for (Movie movie : movieList) {
            if (movie.getTitle().contains(query) || movie.getDirector().contains(query)) {
                filteredMovies.add(movie);
            }
        }

        return filteredMovies;
    }

    private class Movie {
        private final StringProperty title;
        private final StringProperty director;

        public Movie(String title, String director) {
            this.title = new SimpleStringProperty(title);
            this.director = new SimpleStringProperty(director);
        }

        public String getTitle() {
            return title.get();
        }

        public StringProperty titleProperty() {
            return title;
        }

        public void setTitle(String title) {
            this.title.set(title);
        }

        public String getDirector() {
            return director.get();
        }

        public StringProperty directorProperty() {
            return director;
        }

        public void setDirector(String director) {
            this.director.set(director);
        }
    }
}

search-movies.fxml

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

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

<AnchorPane prefHeight="610.0" prefWidth="1024.0" xmlns="http://javafx.com/javafx/10.0.2-internal" xmlns:fx="http://javafx.com/fxml/1" fx:controller="com.lib.controllers.SearchMovies">
   <children>
      <TextField fx:id="searchField" prefHeight="49.0" prefWidth="734.0" AnchorPane.leftAnchor="25.0" AnchorPane.rightAnchor="192.0" AnchorPane.topAnchor="35.0" />
      <Button mnemonicParsing="false" onAction="#search" prefHeight="49.0" prefWidth="155.0" text="SEARCH" AnchorPane.leftAnchor="844.0" AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="35.0" />
      <TableView fx:id="tableView" layoutX="50.0" layoutY="120.0" prefHeight="627.0" prefWidth="974.0" AnchorPane.bottomAnchor="21.0" AnchorPane.leftAnchor="25.0" AnchorPane.rightAnchor="25.0" AnchorPane.topAnchor="120.0">
        <columns>
          <TableColumn fx:id="titleColumn" prefWidth="75.0" text="Title" />
          <TableColumn fx:id="directorColumn" prefWidth="433.0" text="Director" />
            <TableColumn fx:id="likeColumn" prefWidth="215.0" text="Like" />
        </columns>
         <columnResizePolicy>
            <TableView fx:constant="CONSTRAINED_RESIZE_POLICY" />
         </columnResizePolicy>
      </TableView>
   </children>
</AnchorPane>
0 Answers
Related