Binding label with conditional content?

Zephyr :

I have a Label that needs to display the number of elements in an ObservableList. I have the IntegerBinding setup, but I also need to adjust the wording of the Label based on how many elements are in the list.

For the MCVE below, if there is only one element in the list, it should display "The list contains 1 item." But "item" needs to be plural if the list is empty or contains multiple items: "The list contains 3 items."

I have tried to do so using both a ternary operator and a BooleanBinding, but neither has any effect as the ternary expression only seems to be evaluated once. Clicking the "Add" button does not change the "items" portion of the Label.


THE CODE

import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.beans.binding.IntegerBinding;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.geometry.Insets;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;

public class Main extends Application {

    ObservableList<String> items = FXCollections.observableArrayList();

    private IntegerBinding listSize = Bindings.size(items);

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

    @Override
    public void start(Stage primaryStage) {

        // Simple Interface
        VBox root = new VBox(10);
        root.setAlignment(Pos.CENTER);
        root.setPadding(new Insets(10));

        Label label = new Label();

        // Bind the label to display a size-aware notification
        label.textProperty().bind(
                Bindings.concat("The list contains ", listSize,
                        ((items.size() != 1) ? " items!" : " item!"))
        );

        // Button to add items
        Button button = new Button("Add");
        button.setOnAction(event -> items.add("new item"));

        root.getChildren().addAll(label, button);

        // Show the stage
        primaryStage.setScene(new Scene(root));
        primaryStage.setTitle("Sample");
        primaryStage.show();
    }
}


Do I need to include a listener for when the size of the list changes?

JKostikiadis :

Here is a quick solution using a custom StringBinding()

// Bind the label to display a size-aware notification
label.textProperty().bind(new StringBinding() {
    { bind(listSize); }

    @Override
    protected String computeValue() {
        return "The list contains " + listSize.get() + ((items.size() != 1) ? " items!" : " item!");
    }

});

In the code above you will listen to the listSize for changes and then you will create the new String inside the computeValue().

Guess you like

Origin http://43.154.161.224:23101/article/api/json?id=77444&siteId=1