Simple code to reproduce the issue:
import java.util.Random;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* @author Alessio
*/
public class TableViewScrollIssue extends Application {
public class TableViewItem {
private final IntegerProperty id;
private final IntegerProperty value;
public TableViewItem(int id, int value) {
this.id = new SimpleIntegerProperty(id);
this.value = new SimpleIntegerProperty(value);
}
public int getId() {
return id.get();
}
public IntegerProperty idProperty() {
return id;
}
public int getValue() {
return value.get();
}
public IntegerProperty valueProperty() {
return value;
}
}
private GridPane root;
private TableView<TableViewItem> primaryTable;
private TableView<TableViewItem> secondaryTable;
@Override
public void start(Stage primaryStage) {
ObservableList<TableViewItem> items = FXCollections.observableArrayList();
for (int i = 0; i < 50; i++) {
items.add(new TableViewItem(i, (new Random().nextInt(4000))));
}
primaryTable = createTableView();
primaryTable.setItems(items);
primaryTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TableViewItem>() {
@Override
public void changed(ObservableValue<? extends TableViewItem> observable, TableViewItem oldValue, TableViewItem newValue) {
secondaryTable.setItems(null);
if (newValue != null) {
PauseTransition transition = new PauseTransition(Duration.millis(20));
transition.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ObservableList<TableViewItem> items = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
items.add(new TableViewItem(i, (new Random().nextInt(4000))));
}
secondaryTable.setItems(items);
}
});
transition.play();
}
}
});
secondaryTable = createTableView();
root = new GridPane();
ColumnConstraints col = new ColumnConstraints();
col.setFillWidth(true);
col.setPercentWidth(50.0);
root.getColumnConstraints().addAll(col, col);
root.addColumn(0, primaryTable);
root.addColumn(1, secondaryTable);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView createTableView() {
TableView<TableViewItem> view = new TableView<>();
TableColumn<TableViewItem, Integer> colId = new TableColumn("ID");
colId.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<TableViewItem, Integer> colVal = new TableColumn("VALUE");
colVal.setCellValueFactory(new PropertyValueFactory<>("value"));
view.getColumns().add(colId);
view.getColumns().add(colVal);
view.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
view.setPlaceholder(new Label());
return view;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Step to reproduce this issue:
- select an item in the left table
- scroll the items in the right table
- select a new item in the left table. A null pointer exception is thrown.
The pause transition is used to simulate a server request. Without that there isn't this issue.
This issues started from javafx 8u40-ea.
import java.util.Random;
import javafx.animation.PauseTransition;
import javafx.application.Application;
import javafx.beans.property.IntegerProperty;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.value.ChangeListener;
import javafx.beans.value.ObservableValue;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.event.EventHandler;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.scene.layout.ColumnConstraints;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;
import javafx.util.Duration;
/**
*
* @author Alessio
*/
public class TableViewScrollIssue extends Application {
public class TableViewItem {
private final IntegerProperty id;
private final IntegerProperty value;
public TableViewItem(int id, int value) {
this.id = new SimpleIntegerProperty(id);
this.value = new SimpleIntegerProperty(value);
}
public int getId() {
return id.get();
}
public IntegerProperty idProperty() {
return id;
}
public int getValue() {
return value.get();
}
public IntegerProperty valueProperty() {
return value;
}
}
private GridPane root;
private TableView<TableViewItem> primaryTable;
private TableView<TableViewItem> secondaryTable;
@Override
public void start(Stage primaryStage) {
ObservableList<TableViewItem> items = FXCollections.observableArrayList();
for (int i = 0; i < 50; i++) {
items.add(new TableViewItem(i, (new Random().nextInt(4000))));
}
primaryTable = createTableView();
primaryTable.setItems(items);
primaryTable.getSelectionModel().selectedItemProperty().addListener(new ChangeListener<TableViewItem>() {
@Override
public void changed(ObservableValue<? extends TableViewItem> observable, TableViewItem oldValue, TableViewItem newValue) {
secondaryTable.setItems(null);
if (newValue != null) {
PauseTransition transition = new PauseTransition(Duration.millis(20));
transition.setOnFinished(new EventHandler<ActionEvent>() {
@Override
public void handle(ActionEvent event) {
ObservableList<TableViewItem> items = FXCollections.observableArrayList();
for (int i = 0; i < 100; i++) {
items.add(new TableViewItem(i, (new Random().nextInt(4000))));
}
secondaryTable.setItems(items);
}
});
transition.play();
}
}
});
secondaryTable = createTableView();
root = new GridPane();
ColumnConstraints col = new ColumnConstraints();
col.setFillWidth(true);
col.setPercentWidth(50.0);
root.getColumnConstraints().addAll(col, col);
root.addColumn(0, primaryTable);
root.addColumn(1, secondaryTable);
Scene scene = new Scene(root, 600, 400);
primaryStage.setScene(scene);
primaryStage.show();
}
private TableView createTableView() {
TableView<TableViewItem> view = new TableView<>();
TableColumn<TableViewItem, Integer> colId = new TableColumn("ID");
colId.setCellValueFactory(new PropertyValueFactory<>("id"));
TableColumn<TableViewItem, Integer> colVal = new TableColumn("VALUE");
colVal.setCellValueFactory(new PropertyValueFactory<>("value"));
view.getColumns().add(colId);
view.getColumns().add(colVal);
view.setColumnResizePolicy(TableView.CONSTRAINED_RESIZE_POLICY);
view.setPlaceholder(new Label());
return view;
}
/**
* @param args the command line arguments
*/
public static void main(String[] args) {
launch(args);
}
}
Step to reproduce this issue:
- select an item in the left table
- scroll the items in the right table
- select a new item in the left table. A null pointer exception is thrown.
The pause transition is used to simulate a server request. Without that there isn't this issue.
This issues started from javafx 8u40-ea.
- duplicates
-
JDK-8096639 NPE in VirtualFlow
- Resolved