1

Why does the CellFactory add so many null elements in this list? I explicitly set an observable array with just "a" and "b"
I don't think it's a problem with the bindings ... Any suggestions?

package at.kingcastle.misc;

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.collections.FXCollections;
import javafx.scene.Scene;
import javafx.scene.control.ContextMenu;
import javafx.scene.control.ListCell;
import javafx.scene.control.ListView;
import javafx.scene.layout.StackPane;
import javafx.stage.Stage;

public class MainSpielwiese  extends Application {
    @Override
    public void start(Stage primaryStage) {
        ListView<String> lv = new ListView<>();
        lv.setItems(FXCollections.observableArrayList(new String[] {"a", "b"}));

        StackPane root = new StackPane();
        root.getChildren().add(lv);

        Scene scene = new Scene(root, 300, 250);
        primaryStage.setScene(scene);
        primaryStage.show();

        lv.setCellFactory(list -> {
            ListCell<String> cell = new ListCell<>();
            ContextMenu contextMenu = new ContextMenu();
            cell.textProperty().bind(Bindings.format("%s", cell.itemProperty()));
            return cell;
        });
    }

    public static void main(String[] args) {
        launch(args);
    }
}

enter image description here

fabian
  • 80,457
  • 12
  • 86
  • 114
Philipp König
  • 357
  • 2
  • 10

1 Answers1

4

Empty cells always have null as their item.

A string format will format null as the literal string "null" (the string containing the four characters n, u, l, and l). Consequently, your binding will display the text "null" in all the empty cells.

Since you have string data in this column, you can just do

cell.textProperty().bind(cell.itemProperty());

which will set the text to the value null instead of the literal string "null" when the cell is empty.

More generally (i.e. for data types that are not String, so you can't use the binding above), you can do something like

cell.textProperty().bind(Bindings.
    when(cell.emptyProperty()).
    then("").
    otherwise(Bindings.format("%s", cell.itemProperty())));

or

cell.textProperty().bind(Bindings.createStringBinding(() -> {
    if (cell.isEmpty()) {
        return "" ;
    } else {
        return String.format("%s", cell.getItem());
    }
}, cell.itemProperty(), cell.emptyProperty());

or

cell.textProperty().bind(new StringBinding() {
    {
        bind(cell.textProperty(), cell.emptyProperty());
    }
    @Override
    public String computeValue() {
        return cell.isEmpty() ? "" : String.format("%s", cell.getItem()) ;
    }
});
James_D
  • 201,275
  • 16
  • 291
  • 322
  • Thanks, that is exactly what I was looking for :) – Philipp König Feb 09 '18 at 17:23
  • @PhilippKönig See also the [documentation for Cell.updateItem](https://docs.oracle.com/javase/9/docs/api/javafx/scene/control/Cell.html#updateItem-T-boolean-). – VGR Feb 09 '18 at 19:16