When I create a ListView with a custom ListCell that displays a Graphic and no text and then add a single item, clear the list and add multiple other items, the removed items are not really removed and still displayed in the ListView.
Sample Code:
package application;
import java.util.Arrays;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ListViewAddingObjectsAgain extends Application
{
private class Cell extends ListCell<String>
{
@Override
protected void updateItem(final String string, final boolean empty)
{
super.updateItem(string, empty);
if (!empty)
{
final Text text = new Text(string);
final Rectangle rectSmall = new Rectangle(20,20);
rectSmall.setFill(Color.GREEN);
final Rectangle rectLarge = new Rectangle(50,50);
rectLarge.setFill(Color.BLUE);
setText(null);
// use one of the above, results in different versions of the error
setGraphic(rectLarge);
}
}
}
@Override
public void start(final Stage primaryStage)
{
final ObservableList<String> list = FXCollections.observableArrayList();
final ListView<String> view = new ListView<>(list);
view.setCellFactory(v -> new Cell());
final Button aButton = new Button("A");
aButton.setOnAction(event -> { list.clear(); list.addAll(Arrays.asList(new String[] { "A" })); });
final Button bButton = new Button("B");
bButton.setOnAction(event -> { list.clear(); list.addAll(Arrays.asList(new String[] { "B", "C" })); });
final Button clearButton = new Button("clear");
clearButton.setOnAction((event) -> list.clear());
final VBox box = new VBox();
box.getChildren().add(view);
box.getChildren().add(aButton);
box.getChildren().add(bButton);
box.getChildren().add(clearButton);
primaryStage.setScene(new Scene(box));
primaryStage.show();
}
public static void main(final String[] args)
{
launch(args);
}
}
Steps to reproduce:
1) start application
2) click "A" Button
3) click "B" Button
optional
4) click "A" Button
5) click "B" Button
6) repeat 4 + 6, and add press on "clear" from time to time
It is also possible to use the rectSmall or the text Node instead of the rectLarge, in that case there will always be two listcells being displayed:
0) setGraphic(text or rectSmall)
1) start application
2) click "A" Button
3) click "B" Button
4) click "A" Button
Sample Code:
package application;
import java.util.Arrays;
import javafx.application.Application;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.VBox;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Text;
import javafx.stage.Stage;
public class ListViewAddingObjectsAgain extends Application
{
private class Cell extends ListCell<String>
{
@Override
protected void updateItem(final String string, final boolean empty)
{
super.updateItem(string, empty);
if (!empty)
{
final Text text = new Text(string);
final Rectangle rectSmall = new Rectangle(20,20);
rectSmall.setFill(Color.GREEN);
final Rectangle rectLarge = new Rectangle(50,50);
rectLarge.setFill(Color.BLUE);
setText(null);
// use one of the above, results in different versions of the error
setGraphic(rectLarge);
}
}
}
@Override
public void start(final Stage primaryStage)
{
final ObservableList<String> list = FXCollections.observableArrayList();
final ListView<String> view = new ListView<>(list);
view.setCellFactory(v -> new Cell());
final Button aButton = new Button("A");
aButton.setOnAction(event -> { list.clear(); list.addAll(Arrays.asList(new String[] { "A" })); });
final Button bButton = new Button("B");
bButton.setOnAction(event -> { list.clear(); list.addAll(Arrays.asList(new String[] { "B", "C" })); });
final Button clearButton = new Button("clear");
clearButton.setOnAction((event) -> list.clear());
final VBox box = new VBox();
box.getChildren().add(view);
box.getChildren().add(aButton);
box.getChildren().add(bButton);
box.getChildren().add(clearButton);
primaryStage.setScene(new Scene(box));
primaryStage.show();
}
public static void main(final String[] args)
{
launch(args);
}
}
Steps to reproduce:
1) start application
2) click "A" Button
3) click "B" Button
optional
4) click "A" Button
5) click "B" Button
6) repeat 4 + 6, and add press on "clear" from time to time
It is also possible to use the rectSmall or the text Node instead of the rectLarge, in that case there will always be two listcells being displayed:
0) setGraphic(text or rectSmall)
1) start application
2) click "A" Button
3) click "B" Button
4) click "A" Button