Zephyr
Zephyr

Reputation: 10253

Binding label with conditional content?

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?

Upvotes: 4

Views: 1215

Answers (2)

Jai
Jai

Reputation: 8363

This is the shorter equivalent:

label.textProperty().bind(Bindings.createStringBinding(
                              () -> "The list contains " + listSize.get() + ((itemSize.get() != 1) ? " items!" : " item!",
                              listSize
                          ));

Or another alternative:

label.textProperty.bind(Bindings
                           .when(listSize.isEqualTo(1))
                           .then("The list contains 1 item!")
                           .otherwise(
                               Bindings.concat("The list contains " + listSize + " items!")
                           )
                       );

Upvotes: 4

JKostikiadis
JKostikiadis

Reputation: 2917

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().

Upvotes: 3

Related Questions