llenar tabla javafx
Crear una columna de índice de fila en JavaFX (1)
Tengo una JavaFX TableView que estoy completando con una Lista observable de tareas. He intentado crear una columna que muestre el índice de cada fila, que sirve como identificación para las tareas de la tabla, pero he intentado el método aquí y métodos similares de otras fuentes con poco éxito.
Mi código de referencia, que no tiene errores superficiales (por lo que Eclipse puede decir):
@FXML private TableColumn<Task, String> taskIndexCol;
Callback<TableColumn<Task, String>, TableCell<Task, String>> cb =
new Callback<TableColumn<Task, String>, TableCell<Task, String>>(){
@Override
public TableCell<Task, String> call(TableColumn<Task, String> col) {
TableCell<Task, String> cell = new TableCell<Task, String>() {
@Override
protected void updateItem(String item, boolean empty) {
super.updateItem(item, empty);
if (item == null) {
setText("");
} else {
setText(getIndex()+"");
}
}
};
return cell;
}
};
taskIndexCol.setCellFactory(cb);
Actualmente, mi código me da una NullPointerException cuando intento establecer CellFactory de la columna. Lo he intentado con una lista de tareas poblada, pero eso no ayudó. Me he quedado perplejo durante mucho tiempo, y teóricamente, esto debería ser bastante fácil, ya que es solo numerar las filas. Parece que estoy saltando un millón de aros para hacer algo frustrantemente simple.
Editar: La última línea me da el NPE.
Es imposible determinar la causa de la excepción del puntero nulo, porque no ha mostrado el seguimiento de pila, identificado la línea que arroja la excepción o publicado lo suficiente de su código (ninguno de los códigos en su devolución de llamada puede arrojar una excepción de puntero nulo , entonces algo está mal en otro lado).
Para su implementación de celda real, no mostró si tenía un cellValueFactory
establecido en la columna. Si no lo hace, el item
siempre será null
, por lo que nunca verá ningún texto en las celdas de esa columna. Puede verificar la propiedad empty
(o el parámetro de método) como un medio para verificar si la celda está en una fila vacía o en una con datos reales. (Tenga en cuenta que esto significa que la columna realmente no necesita proporcionar ningún dato: puede ser una TableColumn<Task, Void>
).
Además, probablemente sea más seguro confiar en el uso de updateIndex(...)
lugar de updateItem(...)
. Se garantiza que se llamará a updateIndex
cuando el índice cambie; si implementa updateItem
, asume que el índice está establecido antes del elemento, lo que significa que se basa en un detalle de implementación.
Su código es mucho más corto y más fácil de leer si utiliza Java 8 expresiones lambda:
taskIndexCol.setCellFactory(col -> new TableCell<Task, String>() {
@Override
protected void updateIndex(int index) {
super.updateIndex(index);
if (isEmpty() || index < 0) {
setText(null);
} else {
setText(Integer.toString(index));
}
}
});
o alternativamente
taskIndexCol.setCellFactory(col -> {
TableCell<Task, String> cell = new TableCell<>();
cell.textProperty().bind(Bindings.when(cell.emptyProperty())
.then("")
.otherwise(cell.indexProperty().asString()));
return cell ;
});
Aquí hay un 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<Person> table = new TableView<>();
table.setEditable(true);
table.getItems().addAll(
new Person("Jacob", "Smith", "[email protected]"),
new Person("Isabella", "Johnson",
"[email protected]"),
new Person("Ethan", "Williams", "[email protected]"),
new Person("Emma", "Jones", "[email protected]"),
new Person("Michael", "Brown", "[email protected]"));
TableColumn<Person, String> firstNameCol = createColumn("First Name",
Person::firstNameProperty, 150);
TableColumn<Person, String> lastNameCol = createColumn("Last Name",
Person::lastNameProperty, 150);
TableColumn<Person, String> emailCol = createColumn("Email",
Person::emailProperty, 150);
// index column doesn''t even need data...
TableColumn<Person, Void> indexCol = createColumn("Index", person -> null, 50);
// cell factory to display the index:
// indexCol.setCellFactory(col -> {
//
// // just a default table cell:
// TableCell<Person, Void> cell = new TableCell<>();
//
// cell.textProperty().bind(
// when(cell.emptyProperty())
// .then("")
// .otherwise(cell.indexProperty().asString()));
//
// return cell ;
// });
indexCol.setCellFactory(col -> new TableCell<Person, Void>() {
@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 <S, T> TableColumn<S, T> createColumn(String title,
Function<S, ObservableValue<T>> property, double width) {
TableColumn<S, T> 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);
}
}