After trying b94 I have determined that my lists and tables are sometimes getting stuck in an endless loop of updateItem calls on their cells.
It looks like after the fix for bugRT-29923 a ListCell may often get updateItem() called when the item has not actually changed. This stems from the fact that anything that causes a re layout of the cells also seems to cause that all of their indexes get marked as changed and this results in updateItem() being called. Subsequently if there is anything in your updateItem() code that might cause a re layout we end up in an infinite loop of calls.
The following test code will print out a message whenever an unnecessary call to updateItem() happens. You can resize the stage and see it gets printed out quite a lot. If you change the updating strategy in my updateItem() method to always reset the cell ui and then only set it when it has a non-null item you will observe an infinite loop of update calls.
Also if you comment out my custom cell and use the TextFieldListCell I believe this bug also stops the cell from ever fully switching to editing mode. The installing of the textfield causes a re layout which changes all the indexes and results in a call to updateItem() even though the item hasn't changed. And updateItem() cancels the edit.
*******************************************************************
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewTest extends Application {
private static final Image IMAGE = new Image("http://www.oracle.com/ocom/"
+ "groups/public/@otn/documents/digitalasset/1917282.jpg");
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.centerOnScreen();
primaryStage.setHeight(200);
primaryStage.setWidth(550);
final ListView<String> list = new ListView<>();
list.setEditable(true);
list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> param) {
return new ListCell<String>() {
ImageView view = new ImageView();
{setGraphic(view);};
@Override public void updateItem(String item, boolean empty) {
if ( (getItem() == null) ? item == null : getItem().equals(item) ) {
System.out.println("unnecessary update");
}
super.updateItem(item, empty);
if ( item == null || empty ) {
view.setImage(null);
setText(null);
} else {
view.setImage(IMAGE);
setText(item);
}
// this less efficient but valid strategy can cause an
// infinite loop of layouts and updateItem() calls.
//view.setImage(null);
//setText(null);
//if ( item != null ) {
// view.setImage(image);
// setText(item);
//}
}
};
}
});
// if you try the builtin one it will never let you edit cause the
// act of it installing the textfield will cause a layout and this
// calls updateItem which cancels the edit.
//list.setCellFactory(TextFieldListCell.forListView());
list.getItems().setAll("one", "two", "three", "four", "five");
primaryStage.setScene(new Scene(new StackPane(list)));
primaryStage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
It looks like after the fix for bug
The following test code will print out a message whenever an unnecessary call to updateItem() happens. You can resize the stage and see it gets printed out quite a lot. If you change the updating strategy in my updateItem() method to always reset the cell ui and then only set it when it has a non-null item you will observe an infinite loop of update calls.
Also if you comment out my custom cell and use the TextFieldListCell I believe this bug also stops the cell from ever fully switching to editing mode. The installing of the textfield causes a re layout which changes all the indexes and results in a call to updateItem() even though the item hasn't changed. And updateItem() cancels the edit.
*******************************************************************
import javafx.application.Application;
import javafx.scene.Scene;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;
import javafx.util.Callback;
public class ListViewTest extends Application {
private static final Image IMAGE = new Image("http://www.oracle.com/ocom/"
+ "groups/public/@otn/documents/digitalasset/1917282.jpg");
@Override
public void start(Stage primaryStage) throws Exception {
primaryStage.centerOnScreen();
primaryStage.setHeight(200);
primaryStage.setWidth(550);
final ListView<String> list = new ListView<>();
list.setEditable(true);
list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
@Override
public ListCell<String> call(ListView<String> param) {
return new ListCell<String>() {
ImageView view = new ImageView();
{setGraphic(view);};
@Override public void updateItem(String item, boolean empty) {
if ( (getItem() == null) ? item == null : getItem().equals(item) ) {
System.out.println("unnecessary update");
}
super.updateItem(item, empty);
if ( item == null || empty ) {
view.setImage(null);
setText(null);
} else {
view.setImage(IMAGE);
setText(item);
}
// this less efficient but valid strategy can cause an
// infinite loop of layouts and updateItem() calls.
//view.setImage(null);
//setText(null);
//if ( item != null ) {
// view.setImage(image);
// setText(item);
//}
}
};
}
});
// if you try the builtin one it will never let you edit cause the
// act of it installing the textfield will cause a layout and this
// calls updateItem which cancels the edit.
//list.setCellFactory(TextFieldListCell.forListView());
list.getItems().setAll("one", "two", "three", "four", "five");
primaryStage.setScene(new Scene(new StackPane(list)));
primaryStage.show();
}
public static void main(String[] args) throws Exception {
launch(args);
}
}
- relates to
-
JDK-8124826 Cell with null initial value cannot be edited because the empty property is true
- Resolved