Привязка ToggleGroup двунаправленно в javafx
представьте себе, что перечисление, определяющее режимы мыши:
public enum MouseMode {
SELECTION,
EDITING,
DELETING }
и представьте, что у вас есть тумблер-группа из 3 кнопок:
ToggleButton selection = new ToggleButton("Select");
ToggleButton editing = new ToggleButton("Edit");
ToggleButton deleting = new ToggleButton("Delete");
ToggleGroup mouseSelection = new ToggleGroup();
Я хочу, чтобы поле MouseMode currentMode
для двунаправленной связи с переключаемой группой. Всякий раз, когда переключатель установлен, currentMode переключается соответственно, но и если какой-то внешний процесс изменяет currentMode (возможно, нажатие клавиши), то togglegroup адаптируется соответственно.
Я могу сделать это с 2 слушателями, но мне интересно, есть ли способ создайте пользовательскую двунаправленную карту.
3 ответов
Я не думаю, что есть способ сделать это напрямую. Хотя общего назначения
Bindings.bindBidirectional(Property<S> property1, Property<T> property2, Function<S,T> mapping, Function<T,S> inverseMapping)
может стать хорошим дополнением к API, даже это не поможет в этом случае, как ToggleGroup
' s selectedProperty
только для чтения (так как выбор должен обрабатываться, когда каждый Toggle
' s setSelected(...)
вызывается метод, а также с помощью ToggleGroup
' s selectedProperty
).
использование нескольких слушателей-это путь в этом случае.
самое близкое к " custom двунаправленная карта " - это
Bindings.bindBiDirectional(StringProperty stringProperty, ObjectProperty<T> otherProperty, StringConverter<T> converter)
метод. В случае, когда у вас есть (записываемый) ObjectProperty<S>
и (для записи) ObjectProperty<T>
теоретически вы можете использовать две двунаправленные привязки и промежуточное StringProperty
чтобы связать их вместе. На практике это почти всегда больше кода, чем просто использование двух слушателей, а также менее эффективно.
Я успешно использовал класс ToggleGroupValue в проекте JFXtras. Это только в 2.2 кода, а не 8.0, но его достаточно легко скопировать в свой код. https://github.com/JFXtras/jfxtras-labs/blob/2.2/src/main/java/jfxtras/labs/scene/control/ToggleGroupValue.java
вот пример:
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);
}
}
Я использую адаптер свойств Java bean, но вы можете просто использовать последнюю строку этого кода и связать его.
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);
вам нужно иметь небольшой класс BindingUtils для 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());
});
}