我有一个DatePicker
TableCell
的有效实现,但是当我的NullPointerException
尝试检索CellFactory
时,我遇到了TableRow
。 / p>
该异常似乎不会以任何方式影响实际功能,但我不知道是什么原因造成的。
为简便起见,这只是CellFactory
的实现(下面完整的MCVE,但这也许足以让您看到我的错误):
colDatePaid.setCellFactory(col -> new TableCell<Bill, LocalDate>() {
final DatePicker datePicker = new DatePicker();
@Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
System.out.println(getTableRow()); // <-- This prints 'null' only once upon execution
Bill bill = (Bill) getTableRow().getItem();
if (item == null || bill.isDateChanged()) {
bill.datePaidProperty().bind(datePicker.valueProperty());
setGraphic(datePicker);
} else {
setGraphic(new Label(bill.getDatePaid().toString()));
}
}
}
});
println()
方法提供以下输出以及NPE:
null
TableRow@47e536dc[styleClass=cell indexed-cell table-row-cell]'null'
TableRow@1345fc2c[styleClass=cell indexed-cell table-row-cell]'null'
TableRow@44dfbc27[styleClass=cell indexed-cell table-row-cell]'null'
TableRow@5c091f1[styleClass=cell indexed-cell table-row-cell]'null'
TableRow@3b50e9f5[styleClass=cell indexed-cell table-row-cell]'null'
TableRow@17a393fb[styleClass=cell indexed-cell table-row-cell]'null'
正如我所说,该应用程序的运行似乎没有受到影响,但我希望对解决这个特定问题有所帮助。
完整MCVE:
import javafx.application.Application;
import javafx.beans.property.*;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import java.time.LocalDate;
public class ConditionalColumnSample extends Application {
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
// Simple Interface
VBox root = new VBox(10);
root.setAlignment(Pos.CENTER);
root.setPadding(new Insets(10));
// TableView
TableView<Bill> tableView = new TableView<>();
TableColumn<Bill, Number> colAmountDue = new TableColumn<>("Amount Due");
TableColumn<Bill, LocalDate> colDatePaid = new TableColumn<>("Date Paid");
tableView.getColumns().addAll(colAmountDue, colDatePaid);
tableView.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);
// CellValueProperties
colAmountDue.setCellValueFactory(tf -> tf.getValue().amountDueProperty());
colDatePaid.setCellValueFactory(tf -> tf.getValue().datePaidProperty());
// CellFactory for Date Paid column
colDatePaid.setCellFactory(col -> new TableCell<Bill, LocalDate>() {
final DatePicker datePicker = new DatePicker();
@Override
protected void updateItem(LocalDate item, boolean empty) {
super.updateItem(item, empty);
if (empty) {
setGraphic(null);
} else {
System.out.println(getTableRow()); // <-- This prints 'null' only once upon execution
Bill bill = (Bill) getTableRow().getItem();
if (item == null || bill.isDateChanged()) {
bill.datePaidProperty().bind(datePicker.valueProperty());
setGraphic(datePicker);
} else {
setGraphic(new Label(bill.getDatePaid().toString()));
}
}
}
});
// Button to test data
Button button = new Button("Print Values");
button.setOnAction(event -> {
for (Bill bill : tableView.getItems()) {
System.out.println(bill);
}
});
// Sample data
tableView.getItems().addAll(
new Bill(42.34, null),
new Bill(894.99, null),
new Bill(54.87, LocalDate.now()),
new Bill(5.00, null),
new Bill(123.68, LocalDate.of(2019, 12, 25))
);
root.getChildren().addAll(tableView, button);
// Show the stage
primaryStage.setScene(new Scene(root));
primaryStage.setTitle("Sample");
primaryStage.show();
}
}
class Bill {
private DoubleProperty amountDue = new SimpleDoubleProperty();
private ObjectProperty<LocalDate> datePaid = new SimpleObjectProperty<>();
private BooleanProperty dateChanged = new SimpleBooleanProperty();
public Bill(double amountDue, LocalDate datePaid) {
this.amountDue.set(amountDue);
this.datePaid.set(datePaid);
// Listener to determine if the date has been changed
this.datePaidProperty().addListener((observable, oldValue, newValue) -> {
dateChanged.set(true);
});
}
public double getAmountDue() {
return amountDue.get();
}
public void setAmountDue(double amountDue) {
this.amountDue.set(amountDue);
}
public DoubleProperty amountDueProperty() {
return amountDue;
}
public LocalDate getDatePaid() {
return datePaid.get();
}
public void setDatePaid(LocalDate datePaid) {
this.datePaid.set(datePaid);
}
public ObjectProperty<LocalDate> datePaidProperty() {
return datePaid;
}
public boolean isDateChanged() {
return dateChanged.get();
}
public void setDateChanged(boolean dateChanged) {
this.dateChanged.set(dateChanged);
}
public BooleanProperty dateChangedProperty() {
return dateChanged;
}
@Override
public String toString() {
return "Bill{" +
"amountDue=" + amountDue +
", datePaid=" + datePaid +
", dateChanged=" + dateChanged +
'}';
}
}