2014-04-25 14 views
5

Stellen Sie sich eine Enum definieren Maus-Modi mit:Bind ToggleGroup in zwei Richtungen in javafx

public enum MouseMode { 
SELECTION, 
EDITING, 
DELETING } 

Und stellen Sie sich eine Knie Gruppe von 3 Tasten gemacht haben:

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

Ich möchte ein Feld MouseMode currentMode sein bidirektional mit der Toggle-Gruppe verbunden. Wenn ein Toggle gesetzt ist, wird currentMode entsprechend geschaltet, aber auch wenn ein externer Prozess den currentMode ändert (möglicherweise ein Tastendruck), passt sich die Toggle-Gruppe entsprechend an.

Ich kann dies mit 2 Listener tun, aber ich frage mich, ob es eine Möglichkeit gibt, eine benutzerdefinierte bidirektionale Karte zu erstellen.

Antwort

6

Ich glaube nicht, dass es eine Möglichkeit gibt, dies direkt zu tun. Während ein Allzweck-

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

könnte eine gute Ergänzung zu den API machen, auch das wäre in diesem Fall nicht helfen, da die ToggleGroup ‚s selectedProperty nur gelesen (da braucht Auswahl behandelt werden, wenn jedes Toggle‘ s setSelected(...) Methode wird aufgerufen, sowie durch die ToggleGroup 's selectedProperty).

Mit ein paar Listenern ist in diesem Fall der Weg zu gehen.

Die nächste Sache, die "individuelle bidirektionale Karte" ist die

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

Methode. Für den Fall, dass Sie einen (schreibbaren) ObjectProperty<S> und (schreibbar) ObjectProperty<T> haben, können Sie theoretisch zwei bidirektionale Bindungen und ein Zwischenprodukt StringProperty verwenden, um sie miteinander zu verbinden. In der Praxis ist dies fast immer mehr Code als nur zwei Listener zu verwenden, und ist auch weniger effizient.

+1

danke. Ja, ich arbeite an einer kundenspezifischen Bindings.bindBidirectional (Eigenschaft property1, Eigenschaft property2, Funktion Mapping, Funktion inverseMapping), mit etwas Glück wird es gut funktionieren. Aber du hast recht, selectedProperty ist readOnly, also würde das nicht helfen. – CarrKnight

2

Ich habe die ToggleGroupValue-Klasse im JFXtras-Projekt erfolgreich verwendet. Es ist nur in der 2.2 Codebase, nicht die 8.0, aber es ist einfach genug, um in Ihre eigene Codebasis zu kopieren. Hier https://github.com/JFXtras/jfxtras-labs/blob/2.2/src/main/java/jfxtras/labs/scene/control/ToggleGroupValue.java

ist ein Beispiel:

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 unter Wasser? – kleopatra

+0

Scheint Teil von 8.0 zu sein http://jfxtras.org/doc/8.0/jfxtras-controls/jfxtras/scene/control/ToggleGroupValue.html – timdiels

0

I Java Bean-Eigenschaft Adapter bin mit, aber man kann nur die letzte Zeile dieses Codes verwenden und sie binden.

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

Sie müssen eine kleine BindingUtils-Klasse für ToggleGroup haben.

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