ListView in javafx, adds multiple cells


Question

Debugging for the code below, it shows that the updateItem() method is called multiple times, but I am unable to figure out why its being called multiple times.

I wanted to add the Tooltip to the ListView.

// THIS TO ADD TOOLTIP, NOT WORKING FULLY.
lstComments.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
    @Override
    public ListCell<String> call(ListView<String> p) {
        final Tooltip tt = new Tooltip();
        final ListCell<String> cell = new ListCell<String>() {
            String message = ca.getMessage();

            @Override
            public void updateItem(String s, boolean empty) {
                super.updateItem(s, empty);
                tt.setText(message);
                setTooltip(tt);
            }
        };

        cell.setText(ca.getMessage());
        return cell;
    }
});
1
0
8/10/2013 7:03:19 AM

Accepted Answer

Recommendation

I find the usability of Tooltips on ListView cells horrible, because the Tooltips intercept standard mouse events used to select rows, scroll the list, etc. So I would not recommend placing Tooltips on ListView cells.

Why multiple cells are created and updateItem is called multiple times

It is expected that a ListView have multiple cells and that updateItem() is potentially called multiple times for each cell.

A cell is created for every row in the ListView that is displayed on the scene, even if some cells are empty. A couple more cells that are offscreen are usually created for efficient scroll handling. Each time the underlying data for a ListView is initially set or modified, or the list is scrolled, updateItem() will be invoked on relevant cells to update the cell's contents. In the case of scrolling a large list, updateItem() will be invoked many, many times for each cell.

Sample code for setting a Tooltip on ListView Cells

The code below is based on the Oracle JavaFX tutorial ListView sample, but customizes it to create Tooltips for cells when you hover over them.

mport javafx.application.Application;
import javafx.collections.*;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.layout.*;
import javafx.scene.paint.Color;
import javafx.scene.shape.Rectangle;
import javafx.scene.text.Font;
import javafx.stage.Stage;
import javafx.util.Callback;

public class ListViewSample extends Application {

    ListView<String> list = new ListView<String>();
    ObservableList<String> data = FXCollections.observableArrayList(
            "chocolate", "salmon", "gold", "coral", "darkorchid",
            "darkgoldenrod", "lightsalmon", "black", "rosybrown", "blue",
            "blueviolet", "brown");
    final Label label = new Label();

    @Override
    public void start(Stage stage) {
        VBox box = new VBox();
        Scene scene = new Scene(box, 200, 200);
        stage.setScene(scene);
        stage.setTitle("ListViewSample");
        box.getChildren().addAll(list, label);
        VBox.setVgrow(list, Priority.ALWAYS);

        label.setLayoutX(10);
        label.setLayoutY(115);
        label.setFont(Font.font("Verdana", 20));

        list.setItems(data);

        list.setCellFactory(new Callback<ListView<String>, ListCell<String>>() {
            @Override public ListCell<String> call(ListView<String> list) {
                return new ColorRectCell();
            }
        });

        list.getSelectionModel().selectedItemProperty().addListener(
                (ov, old_val, new_val) -> {
                        label.setText(new_val);
                        label.setTextFill(Color.web(new_val));
                });
        stage.show();
    }

    static class ColorRectCell extends ListCell<String> {
        final Rectangle swatch = new Rectangle(30, 30);
        final Tooltip tip = new Tooltip();

        public ColorRectCell() {
            tip.setGraphic(swatch);
        }

        @Override
        public void updateItem(String color, boolean empty) {
            super.updateItem(color, empty);

            if (color != null) {
                swatch.setFill(Color.valueOf(color.toUpperCase()));
                setText(color);
                setTooltip(tip);
            } else {
                setText("");
                setTooltip(null);
            }
        }
    }

    public static void main(String[] args) {
        launch(args);
    }
}
4
8/10/2013 7:45:03 AM

Licensed under: CC-BY-SA with attribution
Not affiliated with: Stack Overflow
Icon