首页 > 解决方案 > 为什么 getTableRow().getItem() 返回一个空引用,即使不是空行?

问题描述

所以我创建了这个带有搜索栏和表格视图的小应用程序。当屏幕初始化时,我使用tableView.setItems()将固定的项目列表添加到我的表中。后来,当用户执行查询时,会生成一个过滤列表,我tableView.setItems()再次调用。当列表被渲染时,我的代码调用方法getRowTable().getItem()来为每一行的按钮添加行为。一切都正确呈现,但是,似乎updateItem()被调用的次数超过了它应该被调用的次数,并getRowTable().getItem()返回一个null使程序抛出异常的引用。

这是什么原因造成的?代码如下。

应用程序.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);
        }
    }
}

搜索-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>

标签: javajavafx

解决方案


推荐阅读