togglegroup java javafx javafx-2 javafx-8

Enlazar ToggleGroup bidireccionalmente en javafx



radio button javafx scene builder (3)

No creo que haya una manera de hacer esto directamente. Si bien es de uso general

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

podría ser una buena adición a la API, incluso eso no ayudaría en este caso, ya que la ToggleGroup selectedProperty ToggleGroup es de solo lectura (ya que la selección debe ser manejada cuando se invoca cada método Toggle ''s setSelected(...) , así como por la ToggleGroup selectedProperty ToggleGroup ).

Usar un par de oyentes es el camino a seguir en este caso.

Lo más parecido al "mapa bidireccional personalizado" es el

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

método. En el caso en que tenga ObjectProperty<S> ( ObjectProperty<S> ) ObjectProperty<S> y ObjectProperty<T> (escribible), en teoría puede usar dos enlaces bidireccionales y un StringProperty intermedio para unirlos. En la práctica, esto es casi siempre más código que simplemente usar dos oyentes, y también es menos eficiente.

Imagine tener una enumeración que defina los modos de mouse:

public enum MouseMode { SELECTION, EDITING, DELETING }

E imagine tener un grupo de alternar compuesto por 3 botones:

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

Quiero que un campo MouseMode currentMode esté vinculado bidireccionalmente al grupo de alternar. Cada vez que se establece un alternar, currentMode se cambia en consecuencia, pero también si algún proceso externo cambia currentMode (tal vez una pulsación de tecla), entonces el togglegroup se adapta en consecuencia.

Puedo hacer esto con 2 oyentes, pero me pregunto si hay una manera de crear un mapa bidireccional personalizado.


He utilizado con éxito la clase ToggleGroupValue en el proyecto JFXtras. Está solo en la base de código 2.2, no en la 8.0, pero es lo suficientemente fácil de copiar a su propia base de código. https://github.com/JFXtras/jfxtras-labs/blob/2.2/src/main/java/jfxtras/labs/scene/control/ToggleGroupValue.java

Aquí hay un ejemplo:

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); } }


Estoy usando un adaptador de propiedad de Java Bean, pero puedes usar la última línea de este código y vincularlo.

JavaBeanObjectProperty<fooEnum> property = null; try { property = new JavaBeanObjectPropertyBuilder<fooEnum>().bean(fooBean).name(fooField).build(); } catch (NoSuchMethodException e1) { e1.printStackTrace(); } property.addListener((obs, oldValue, newValue) -> { System.out.println("Property value changed from " + oldValue + " to " + newValue); }); BindingUtils.bindToggleGroupToProperty(fooToggleGroup, property);

Necesitas tener una pequeña clase BindingUtils para ToggleGroup.

public final class BindingUtils { private BindingUtils() { } public static <T> void bindToggleGroupToProperty(final ToggleGroup toggleGroup, final ObjectProperty<T> property) { // Check all toggles for required user data toggleGroup.getToggles().forEach(toggle -> { if (toggle.getUserData() == null) { throw new IllegalArgumentException("The ToggleGroup contains at least one Toggle without user data!"); } }); // Select initial toggle for current property state for (Toggle toggle : toggleGroup.getToggles()) { if (property.getValue() != null && property.getValue().equals(toggle.getUserData())) { toggleGroup.selectToggle(toggle); break; } } // Update property value on toggle selection changes toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> { property.setValue((T) newValue.getUserData()); }); }