Featured Post

Applying Email Validation to a JavaFX TextField Using Binding

This example uses the same controller as in a previous post but adds a use case to support email validation.  A Commons Validator object is ...

Monday, July 11, 2016

Binding a JavaFX ChoiceBox to a Label

If you're coming from a Swing background, you're used to adding listeners to controls and using programming logic to map the values into controls.  JavaFX Binding offers a clean declarative syntax that avoids the often trivial packing and unpacking of data structures.

This example drives the contents of a Label off of a ChoiceBox. The Bindings.selectString() line associates the selected ChoiceBox item -- a model object -- with the Label.  Since the Label only displays a text value, there is an additional conversion to dig out the "description" property.

This file, ChoiceBoxApp, is a single ChoiceBox paired with a Label via JavaFX Binding.

package cb;

import cb.model.*;
import javafx.application.Application;
import javafx.beans.binding.Bindings;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.ChoiceBox;
import javafx.scene.control.Label;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import javafx.util.StringConverter;

public class ChoiceBoxApp extends Application {

    @Override
    public void start(Stage primaryStage) throws Exception {

        ChoiceBox<Enemy> cbEnemy = new ChoiceBox< >();

        cbEnemy.getItems().add( new Enemy() );  // null item clears label
        cbEnemy.getItems().add( new LightGrineer("Light Grineer"));
        cbEnemy.getItems().add( new MediumGrineer("Medium Grineer"));
        cbEnemy.getItems().add( new HeavyGrineer("Heavy Grineer"));
        cbEnemy.getItems().add( new LightCorpus("Light Corpus"));
        cbEnemy.getItems().add( new MediumCorpus("Medium Corpus"));
        cbEnemy.getItems().add( new HeavyCorpus("Heavy Corpus"));
        cbEnemy.getItems().add( new LightInfested("Light Infested"));
        cbEnemy.getItems().add( new MediumInfested("Medium Infested"));
        cbEnemy.getItems().add( new HeavyInfested("Heavy Infested"));

        cbEnemy.setConverter(new StringConverter() {
            @Override
            public String toString(Enemy object) {
                return object.getDescription();
            }

            @Override
            public Enemy fromString(String string) {
                return null;
            }
        });

        cbEnemy.getSelectionModel().select(0);  // select the first empty item

        Label lblDescription = new Label();  // "DescriptionPane"

        lblDescription.textProperty().bind( Bindings.selectString(cbEnemy.getSelectionModel().selectedItemProperty(), "description") );

        VBox vbox = new VBox();
        vbox.setAlignment(Pos.CENTER);
        vbox.setSpacing( 40.0d );
        vbox.getChildren().add( cbEnemy );
        vbox.getChildren().add( lblDescription );

        Scene scene = new Scene( vbox, 568, 320 );

        primaryStage.setScene( scene );
        primaryStage.show();

    }

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

The app works with several model classes.  "Enemy" is a super class that also will handle an unspecified enemy through a blank selection in the ChoiceBox.  "LightGrineer" is one of several similar classes that extend Enemy.  I didn't print them all for brevity.

public class Enemy {
    private String description = "";  // displayed for empty obj

    public String getDescription() {
        return description;
    }

    public void setDescription(String description) {
        this.description = description;
    }

    public Enemy() {
    }

    public Enemy(String description) {
        setDescription(description);
    }
}

And LightGrineer

public class LightGrineer extends Enemy {
    public LightGrineer(String d) {
        super(d);
    }
}

There is a warning message you get when running the app.  It seems harmless as selecting items correctly updates the Label.  I'll update the post if I find anything interesting out.

Update

I was getting the following warning when I started the app.  This was before I made any selections on the ChoiceBox.

Jul 11, 2016 8:13:45 PM com.sun.javafx.binding.SelectBinding$SelectBindingHelper getObservableValue
WARNING: Exception while evaluating select-binding [description]

I fixed the warning message by making sure that the ChoiceBox's selectionModel started with a selected item.  Apparently, the warning was from trying to bind to a property that wasn't initialized.  Making sure that I made this call prior to binding on the lblDescription dispelled the error.

        
cbEnemy.getSelectionModel().select(0);  // select the first empty item

No comments:

Post a Comment