我有一个表视图,其中填充了我在控制器中创建的动态列。 我第一次创建表时一切正常,但是当我尝试使用新项重绘表时,我得到一个空指针异常,这似乎是由我使用的一些嵌套列引起的(从读取堆栈跟踪)。重新绘制表格时,我采取了与第一次创建时相同的步骤:
删除所有商品(首先使用清除,然后使用全部删除,只是为了确保)
tableFullTimetable.getItems().clear();
tableFullTimetable.getItems().removeAll();
删除所有列(与列相同)
tableFullTimetable.getColumns().clear();
tableFullTimetable.getColumns().removeAll();
然后我使用for循环添加动态嵌套列,然后在表上设置新项
tableFullTimetable.setItems(myNewItems);
我理解表视图有刷新问题,但我认为这是不同的,表被清除但是当执行到达设置行时它会抛出空指针异常,这里是错误的堆栈跟踪:
Exception in thread "JavaFX Application Thread" java.lang.NullPointerException
at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.dispose(NestedTableColumnHeader.java:323)
at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.updateTableColumnHeaders(NestedTableColumnHeader.java:265)
at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.checkState(NestedTableColumnHeader.java:519)
at com.sun.javafx.scene.control.skin.NestedTableColumnHeader.computePrefHeight(NestedTableColumnHeader.java:401)
at javafx.scene.Parent.prefHeight(Parent.java:918)
at javafx.scene.layout.Region.prefHeight(Region.java:1438)
at com.sun.javafx.scene.control.skin.TableHeaderRow.computePrefHeight(TableHeaderRow.java:344)
at com.sun.javafx.scene.control.skin.TableHeaderRow.computeMinHeight(TableHeaderRow.java:339)
at javafx.scene.Parent.minHeight(Parent.java:946)
at javafx.scene.layout.Region.minHeight(Region.java:1404)
at javafx.scene.control.SkinBase.computeMinHeight(SkinBase.java:254)
at javafx.scene.control.Control.computeMinHeight(Control.java:485)
at javafx.scene.Parent.minHeight(Parent.java:946)
at javafx.scene.layout.Region.minHeight(Region.java:1404)
at javafx.scene.layout.Region.computeChildMinAreaHeight(Region.java:1700)
at javafx.scene.layout.BorderPane.getAreaHeight(BorderPane.java:618)
at javafx.scene.layout.BorderPane.computeMinHeight(BorderPane.java:415)
at javafx.scene.Parent.minHeight(Parent.java:946)
at javafx.scene.layout.Region.minHeight(Region.java:1404)
at javafx.scene.layout.Region.boundedNodeSizeWithBias(Region.java:1920)
at javafx.scene.layout.Region.layoutInArea(Region.java:2326)
at javafx.scene.layout.Region.layoutInArea(Region.java:2241)
at javafx.scene.layout.Region.layoutInArea(Region.java:2182)
at javafx.scene.layout.StackPane.layoutChildren(StackPane.java:351)
at javafx.scene.Parent.layout(Parent.java:1076)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Parent.layout(Parent.java:1082)
at javafx.scene.Scene.doLayoutPass(Scene.java:576)
at javafx.scene.Scene$ScenePulseListener.pulse(Scene.java:2386)
at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:321)
at com.sun.javafx.tk.Toolkit$3.run(Toolkit.java:319)
at java.security.AccessController.doPrivileged(Native Method)
at com.sun.javafx.tk.Toolkit.runPulse(Toolkit.java:319)
at com.sun.javafx.tk.Toolkit.firePulse(Toolkit.java:348)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:479)
at com.sun.javafx.tk.quantum.QuantumToolkit.pulse(QuantumToolkit.java:460)
at com.sun.javafx.tk.quantum.QuantumToolkit$13.run(QuantumToolkit.java:327)
at com.sun.glass.ui.InvokeLaterDispatcher$Future.run(InvokeLaterDispatcher.java:95)
at com.sun.glass.ui.win.WinApplication._runLoop(Native Method)
at com.sun.glass.ui.win.WinApplication.access$300(WinApplication.java:39)
at com.sun.glass.ui.win.WinApplication$4$1.run(WinApplication.java:112)
at java.lang.Thread.run(Thread.java:745)
设置到表的可观察集合是一个可观察的arraylist,它没有任何null项。我不知道在上述过程中我错过了什么,请帮助谢谢
更新 这是为了说明我的代码是如何工作的,我没有成功再现这个MCVE中的错误,但我希望它可以帮助你帮助我:)
public class TestTable extends Application {
private TableView<ERoom> tableFullTimetable = new TableView<>();
private String[] days = {"monday", "tuesday", "wednesday", "thursday", "friday"};
private Integer[] timeslots = {1, 2, 3, 4, 5};
private List<ERoom> eRooms;
public static void main(String[] args) {
launch(args);
}
@Override
public void start(Stage primaryStage) {
VBox rootlayout = new VBox();
primaryStage.setWidth(895);
primaryStage.setHeight(550);
primaryStage.setScene(new Scene(rootlayout));
primaryStage.show();
eRooms = new ArrayList<>();
eRooms.add(new ERoom("room1"));
eRooms.add(new ERoom("room2"));
List<ELesson> eLessons = new ArrayList<>();
eLessons.add(new ELesson(2, "friday", eRooms.get(0)));
eLessons.add(new ELesson(4, "wednesday", eRooms.get(1)));
eLessons.add(new ELesson(5, "monday", eRooms.get(1)));
eLessons.add(new ELesson(1, "tuesday", eRooms.get(0)));
eLessons.add(new ELesson(3, "thursday", eRooms.get(1)));
ETimetable firstTimetable = new ETimetable(eLessons, eRooms);
//Load the first timetable
setTimeTable(firstTimetable);
//Button for loading a different timetable
Button button = new Button("Load second timetable");
rootlayout.getChildren().add(tableFullTimetable);
button.onActionProperty().addListener(new ChangeListener<EventHandler<ActionEvent>>() {
@Override
public void changed(ObservableValue<? extends EventHandler<ActionEvent>> observable, EventHandler<ActionEvent> oldValue, EventHandler<ActionEvent> newValue) {
List<ELesson> othereLessons = new ArrayList<>();
othereLessons.add(new ELesson(3, "tuesday", eRooms.get(0)));
othereLessons.add(new ELesson(4, "monday", eRooms.get(1)));
othereLessons.add(new ELesson(2, "friday", eRooms.get(1)));
othereLessons.add(new ELesson(5, "wednesday", eRooms.get(0)));
ETimetable secondtimetable = new ETimetable(othereLessons, eRooms);
setTimeTable(secondtimetable);
}
});
rootlayout.getChildren().add(button);
}
private void setTimeTable(ETimetable newtimetable) {
if (tableFullTimetable.getItems() != null) {
tableFullTimetable.getItems().clear();
tableFullTimetable.getItems().removeAll();
}
if (tableFullTimetable.getColumns() != null) {
tableFullTimetable.getColumns().clear();
tableFullTimetable.getColumns().removeAll();
}
//Nested loops for creating columns
for (String day : days) {
TableColumn dayTableColumn = new TableColumn(day);
tableFullTimetable.getColumns().add(dayTableColumn);
for (int timeslot : timeslots) {
TableColumn<ERoom, ELesson> timeslotTableColumn = new TableColumn<>(Integer.toString(timeslot));
timeslotTableColumn.setPrefWidth(50);
timeslotTableColumn.setCellValueFactory(param -> {
for (ELesson lesson : newtimetable.getLessons()) {
//Return the lesson that matches this column's room and day+timeslot
if (lesson.getRoom().equals(param.getValue()) && lesson.getDay().equals(day) && lesson.getTimeslot() == timeslot) {
return new ReadOnlyObjectWrapper<ELesson>(lesson);
}
}
return null;
});
dayTableColumn.getColumns().add(timeslotTableColumn);
}
}
//This is where it fails
tableFullTimetable.setItems(FXCollections.observableArrayList(newtimetable.getRooms()));
}
private class ETimetable {
private List<ELesson> lessons;
private List<ERoom> rooms;
private ETimetable(List<ELesson> lessons, List<ERoom> rooms) {
this.lessons = lessons;
this.rooms = rooms;
}
public List<ELesson> getLessons() {
return lessons;
}
public List<ERoom> getRooms() {
return rooms;
}
}
private class ELesson {
private int timeslot;
private String day;
private ERoom room;
private ELesson(int timeslot, String day, ERoom room) {
this.timeslot = timeslot;
this.day = day;
this.room = room;
}
public int getTimeslot() {
return timeslot;
}
public String getDay() {
return day;
}
public ERoom getRoom() {
return room;
}
@Override
public String toString() {
return day + " at " + timeslot + " in " + room.getName();
}
}
private class ERoom {
String name;
private ERoom(String name) {
this.name = name;
}
public String getName() {
return name;
}
}
}