Bind ToggleGroup bidirectionally in javafx


Question

Imagine having an enum defining mouse-modes:

public enum MouseMode {
SELECTION,
EDITING,
DELETING }

And imagine having a toggle-group made of 3 buttons:

    ToggleButton selection = new ToggleButton("Select");
    ToggleButton editing = new ToggleButton("Edit");
    ToggleButton deleting = new ToggleButton("Delete");
    ToggleGroup mouseSelection = new ToggleGroup();

I want a field MouseMode currentMode to be bidirectionally linked to the toggle-group. Whenever a toggle is set, currentMode is switched accordingly but also if some external process changes currentMode (maybe a key press) then the togglegroup adapts accordingly.

I can do this with 2 listeners but I wonder if there is a way to create a custom bidirectional map.

1
7
4/25/2014 9:09:09 PM

Accepted Answer

I don't think there is a way to do this directly. While a general-purpose

Bindings.bindBidirectional(Property<S> property1, Property<T> property2, Function<S,T> mapping, Function<T,S> inverseMapping)

might make a good addition to the API, even that wouldn't help in this case as the ToggleGroup's selectedProperty is read only (since selection needs to be handled when each Toggle's setSelected(...) method is invoked, as well as by the ToggleGroup's selectedProperty).

Using a couple of listeners is the way to go in this case.

The closest thing to the "custom bidirectional map" is the

Bindings.bindBiDirectional(StringProperty stringProperty, ObjectProperty<T> otherProperty, StringConverter<T> converter)

method. In the case where you have an (writeable) ObjectProperty<S> and (writeable) ObjectProperty<T> you can in theory use two bidirectional bindings and an intermediate StringProperty to bind them together. In practice, this is almost always more code than just using two listeners, and is also less efficient.

8
4/26/2014 10:50:15 PM

I have successfully made use of the ToggleGroupValue class in the JFXtras project. It is only in the 2.2 codebase, not the 8.0, but it is easy enough to copy to your own codebase. https://github.com/JFXtras/jfxtras-labs/blob/2.2/src/main/java/jfxtras/labs/scene/control/ToggleGroupValue.java

Here is an example:

import java.util.Arrays;
import java.util.List;
import javafx.application.Application;
import javafx.beans.property.SimpleStringProperty;
import javafx.beans.property.StringProperty;
import javafx.scene.Scene;
import javafx.scene.control.Label;
import javafx.scene.control.RadioButton;
import javafx.scene.layout.GridPane;
import javafx.stage.Stage;

public class Main extends Application {
    Child myChild = new Child();
    @Override
    public void start( Stage stage ) throws Exception {
        stage.setTitle( "ToggleGroupValue Example" );
        GridPane gridPane = new GridPane();
        int rowIndex = 0;
        gridPane.add( new Label("Nickname: "), 0, rowIndex );

        ToggleGroupValue toggleGroupValue = new ToggleGroupValue();
        rowIndex = createAddRadioButtons( gridPane, rowIndex, toggleGroupValue );

        gridPane.add( new Label("Selected Nickname: "), 0, rowIndex );
        Label selectedNickNameValueLabel = new Label();
        gridPane.add( selectedNickNameValueLabel, 1, rowIndex );

        myChild.nicknameProperty().bindBidirectional( toggleGroupValue.valueProperty() );
        selectedNickNameValueLabel.textProperty().bind( toggleGroupValue.valueProperty() );

        stage.setScene( new Scene( gridPane, 300, 100 ) );
        stage.show();
    }

    private int createAddRadioButtons( GridPane gridPane, int rowIndex, ToggleGroupValue toggleGroupValue ) {
        RadioButton radioButtonPunkin = new RadioButton();
        radioButtonPunkin.setUserData( "Punkin" );
        RadioButton radioButtonLittleBoy = new RadioButton();
        radioButtonLittleBoy.setUserData( "Little Boy" );
        RadioButton radioButtonBuddy = new RadioButton();
        radioButtonBuddy.setUserData( "Buddy" );
        List<RadioButton> radioButtons = Arrays.asList( radioButtonPunkin, radioButtonLittleBoy, radioButtonBuddy );
        for ( RadioButton radioButton : radioButtons ) {
            toggleGroupValue.add( radioButton, radioButton.getUserData() );
            radioButton.setText( radioButton.getUserData().toString() );
            gridPane.add( radioButton, 1, rowIndex++ );
        }
        return rowIndex;
    }

    private static class Child {
        private StringProperty nickname = new SimpleStringProperty();
        public StringProperty nicknameProperty() {
            return nickname;
        }
        public String getNickname() {
            return nickname.get();
        }
        public void setNickname( String notesProperty ) {
            this.nickname.set( notesProperty );
        }
    }

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

screenshot of javafx example application


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