2014-04-25 13 views
5

Immagina di avere un enum che definisce mouse-modalità:Bind ToggleGroup bidirezionale in JavaFX

public enum MouseMode { 
SELECTION, 
EDITING, 
DELETING } 

E Immaginate di avere una ginocchiera gruppo composto da 3 pulsanti:

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

Voglio un campo MouseMode currentMode di essere collegato bidirezionalmente al gruppo di attivazione/disattivazione. Ogni volta che si imposta un interruttore, currentMode viene commutato di conseguenza, ma anche se un processo esterno cambia il modo corrente (forse una pressione di un tasto), il gruppo di toggette si adatta di conseguenza.

Posso farlo con 2 ascoltatori ma mi chiedo se esiste un modo per creare una mappa bidirezionale personalizzata.

risposta

6

Non penso che ci sia un modo per farlo direttamente. Mentre un generico

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

potrebbe fare una buona aggiunta alla API, anche questo non aiuterebbe in questo caso il ToggleGroup 's selectedProperty è solo (letta dal selezione deve essere gestito quando ogni Toggle' s Il metodo setSelected(...) viene richiamato, così come dal numero ToggleGroup di selectedProperty).

Utilizzare un paio di ascoltatori è la strada da percorrere in questo caso.

La cosa più vicina alla "mappa bidirezionale custom" è il metodo

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

. Nel caso in cui si disponga di uno (scrivibile) ObjectProperty<S> e (scrivibile) ObjectProperty<T> è possibile in teoria utilizzare due binding bidirezionali e uno intermedio StringProperty per unirli tra loro. In pratica, questo è quasi sempre un codice più che usare solo due listener ed è anche meno efficiente.

+1

grazie. Sì, sto lavorando su una proprietà personalizzata Bindings.bindBidirectional (Proprietà property1, Proprietà property2, Funzione mapping, Funzione inverseMapping), con un po 'di fortuna funzionerà perfettamente. Ma hai ragione, selectedProperty è readOnly così che non sarebbe di aiuto. – CarrKnight

2

Ho utilizzato con successo la classe ToggleGroupValue nel progetto JFXtras. È solo nella base di codice 2.2, non nella 8.0, ma è abbastanza facile da copiare nella propria base di codice. https://github.com/JFXtras/jfxtras-labs/blob/2.2/src/main/java/jfxtras/labs/scene/control/ToggleGroupValue.java

Ecco un esempio:

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

+0

tbee sott'acqua? – kleopatra

+0

Sembra essere parte di 8.0 troppo http://jfxtras.org/doc/8.0/jfxtras-controls/jfxtras/scene/control/ToggleGroupValue.html – timdiels

0

Sto utilizzando l'adattatore di proprietà bean Java, ma si può semplicemente utilizzare l'ultima riga di questo codice e associarlo.

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

È necessario disporre di una piccola classe BindingUtils per 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()); 
    }); 
}