在JavaFX中创建行索引列

我有一个JavaFX TableView,我正在使用ObservableList of Tasks填充。 我一直在尝试创建一个显示每行索引的列,它作为表中任务的ID,但我在这里尝试了这个方法,其他来源的类似方法也没有成功。

我的代码供参考,没有表面错误(就Eclipse而言):

@FXML private TableColumn taskIndexCol; Callback<TableColumn, TableCell> cb = new Callback<TableColumn, TableCell>(){ @Override public TableCell call(TableColumn col) { TableCell cell = new TableCell() { @Override protected void updateItem(String item, boolean empty) { super.updateItem(item, empty); if (item == null) { setText(""); } else { setText(getIndex()+""); } } }; return cell; } }; taskIndexCol.setCellFactory(cb); 

目前,当我尝试设置列的CellFactory时,我的代码给了我一个NullPointerException。 我已经尝试了一个填充的任务列表,但这没有帮助。 我已经被困了很长时间了 – 理论上这应该很简单,因为它只是对行进行编号? 感觉就像我正在跳过一百万个箍来做一些令人沮丧的简单事情。

编辑:最后一行给了我NPE。

告诉Null指针exception的原因是不可能的,因为你没有显示堆栈跟踪,识别出抛出exception的行,或者发布了足够的代码(回调中的代码都没有抛出空指针exception) ,所以其他地方出了问题)。

对于实际的单元格实现,您没有显示是否在列上设置了cellValueFactory 。 如果不这样做,那么该项将始终null ,因此您永远不会在该列的单元格中看到任何文本。 您可以检查empty属性(或方法参数),以检查单元格是空行还是具有实际数据。 (注意这意味着该列实际上根本不需要提供任何数据:它可以是TableColumn 。)

此外,依赖于使用updateIndex(...)而不是updateItem(...)可能更安全。 保证在索引改变时调用updateIndex ; 如果您实现updateItem ,则假设在项目之前设置了索引,这意味着您依赖于实现细节。

如果使用Java 8 lambda表达式,您的代码会更短,更容易阅读:

 taskIndexCol.setCellFactory(col -> new TableCell() { @Override protected void updateIndex(int index) { super.updateIndex(index); if (isEmpty() || index < 0) { setText(null); } else { setText(Integer.toString(index)); } } }); 

或者

 taskIndexCol.setCellFactory(col -> { TableCell cell = new TableCell<>(); cell.textProperty().bind(Bindings.when(cell.emptyProperty()) .then("") .otherwise(cell.indexProperty().asString())); return cell ; }); 

这是一个SSCCE:

 import java.util.function.Function; import static javafx.beans.binding.Bindings.when ; import javafx.application.Application; import javafx.beans.binding.Bindings; import javafx.beans.property.SimpleStringProperty; import javafx.beans.property.StringProperty; import javafx.beans.value.ObservableValue; import javafx.scene.Scene; import javafx.scene.control.TableCell; import javafx.scene.control.TableColumn; import javafx.scene.control.TableView; import javafx.scene.layout.BorderPane; import javafx.stage.Stage; public class TableViewWithIndexColumn extends Application { @Override public void start(Stage primaryStage) { TableView table = new TableView<>(); table.setEditable(true); table.getItems().addAll( new Person("Jacob", "Smith", "jacob.smith@example.com"), new Person("Isabella", "Johnson", "isabella.johnson@example.com"), new Person("Ethan", "Williams", "ethan.williams@example.com"), new Person("Emma", "Jones", "emma.jones@example.com"), new Person("Michael", "Brown", "michael.brown@example.com")); TableColumn firstNameCol = createColumn("First Name", Person::firstNameProperty, 150); TableColumn lastNameCol = createColumn("Last Name", Person::lastNameProperty, 150); TableColumn emailCol = createColumn("Email", Person::emailProperty, 150); // index column doesn't even need data... TableColumn indexCol = createColumn("Index", person -> null, 50); // cell factory to display the index: // indexCol.setCellFactory(col -> { // // // just a default table cell: // TableCell cell = new TableCell<>(); // // cell.textProperty().bind( // when(cell.emptyProperty()) // .then("") // .otherwise(cell.indexProperty().asString())); // // return cell ; // }); indexCol.setCellFactory(col -> new TableCell() { @Override public void updateIndex(int index) { super.updateIndex(index); if (isEmpty() || index < 0) { setText(null); } else { setText(Integer.toString(index)); } } }); table.getColumns().add(indexCol); table.getColumns().add(firstNameCol); table.getColumns().add(lastNameCol); table.getColumns().add(emailCol); primaryStage.setScene(new Scene(new BorderPane(table), 600, 400)); primaryStage.show(); } private  TableColumn createColumn(String title, Function> property, double width) { TableColumn col = new TableColumn<>(title); col.setCellValueFactory(cellData -> property.apply(cellData.getValue())); col.setPrefWidth(width); return col; } public static class Person { private final StringProperty firstName = new SimpleStringProperty(); private final StringProperty lastName = new SimpleStringProperty(); private final StringProperty email = new SimpleStringProperty(); public Person() { this("", "", ""); } public Person(String firstName, String lastName, String email) { setFirstName(firstName); setLastName(lastName); setEmail(email); } public final StringProperty firstNameProperty() { return this.firstName; } public final java.lang.String getFirstName() { return this.firstNameProperty().get(); } public final void setFirstName(final java.lang.String firstName) { this.firstNameProperty().set(firstName); } public final StringProperty lastNameProperty() { return this.lastName; } public final java.lang.String getLastName() { return this.lastNameProperty().get(); } public final void setLastName(final java.lang.String lastName) { this.lastNameProperty().set(lastName); } public final StringProperty emailProperty() { return this.email; } public final java.lang.String getEmail() { return this.emailProperty().get(); } public final void setEmail(final java.lang.String email) { this.emailProperty().set(email); } } public static void main(String[] args) { launch(args); } }