Можно ли привязать TextProperty к атрибуту String ObjectProperty, если это не свойство String? - PullRequest
1 голос
/ 03 июня 2019

Как связать атрибут ObjectProperty (который сам по себе не является свойством) с каким-либо другим свойством, таким как текстовое свойство TextField, без использования ChangeListener?

Более конкретно:

Я бы хотел TextField изменить атрибут ObjectProperty.

Пример кода:

MapDTO:

public class MapDTO {
    private String cityName;

    public String getCityName() {
        return cityName;
    }

    public void setCityName(String cityName) {
        this.cityName = cityName;
    }
}

MapsManager:

public class MapsManager {

    private static ObjectProperty<MapDTO> map = new SimpleObjectProperty<>();

    public static MapDTO getMap() {
        return map.get();
    }

    public static ObjectProperty<MapDTO> mapProperty() {
        return map;
    }

    public static void setMap(MapDTO map) {
        MapsManager.map.set(map);
    }
}

BindingTestController:

public class BindingTestController {

    private TextField cityNameTF = new TextField();

    private void initialize() {

        // Bind the cityName label to the selected MapsManager mapProperty's cityName   
        cityNameTF.textProperty().bind(Bindings.createStringBinding(
            () -> MapsManager.mapProperty().getValue() == null ? null :
                MapsManager.mapProperty().getValue().getCityName(),
            MapsManager.mapProperty()));
    }
}

Я пробовал:

Создание строкового свойства из выбранного значения атрибута String, но оно не сработало, и я не смог найти правильный путь.

cityNameTF.textProperty().bindBidirectional(Bindings.createStringBinding(
() -> selectMapCB.getValue() == null ? null : selectMapCB.getValue().getCityName(), 
selectMapCB.valueProperty()));

Создание строкового свойства из атрибута String mapProperty.

cityNameTF.textProperty().bindBidirectional(Bindings.createStringBinding(
() -> MapsManager.getMapProperty().getValue() == null ? null : MapsManager.mapProperty().getValue().getCityName(),
MapsManager.mapProperty()));

Обе опции дают одинаковую ошибку:

bindBidirectional (javafx.beans.property.Property<java.lang.String>)
in StringProperty cannot be applied to (javafx.beans.binding.StringBinding)

В обоих случаях замена bindBidirectional на bind работает, но тогда я не могу изменить текст в TextField. Я понял, что это потому, что я связываю текст TextField со строкой cityName. Поэтому я подумал о том, чтобы связать его одним способом, но в противоположном направлении, что-то вроде:

MapsManager.mapProperty().????.bind(cityNameTF.textProperty());

Но "????" - У меня нет свойства для String, и я не знаю, как создать StringBinding или StringProperty на лету, если это вообще возможно.

Как вручную создать привязку String между атрибутом ObjectProperty и другим StringProperty?

1 Ответ

0 голосов
/ 09 июня 2019

Ваш MapDTO - это, по сути, JavaBean - класс с полем, его получателем и установщиком. Мы назовем такое поле свойством бина . Поскольку вы не можете связать эти свойства или получить их, JavaFX предоставляет адаптеры, которые связывают их со свойствами JavaFX. Они находятся в пакете javafx.beans.property.adapter :

Предоставляет различные классы, которые действуют как адаптеры между обычным свойством Java Bean и соответствующим свойством JavaFX.

Внутренне они функционируют как оболочки свойства bean.

Поскольку ваш MapDTO содержит String, мы будем использовать JavaBeanStringProperty . Обратите внимание:

Как минимум, класс Java Bean должен реализовывать метод получения и установки для свойства. Класс, а также методы getter и setter должны быть объявлены как public.

поэтому мы соблюдаем требования.

Мы создаем эти адаптеры с их строителями, JavaBeanStringPropertyBuilder в этом случае:

JavaBeanStringProperty cityNameProperty = JavaBeanStringPropertyBuilder.create()
                                              .bean(MapsManager.getMap())
                                              .name("cityName")
                                              .build();

Строители обращаются к данным рефлексивно. Теперь мы можем использовать созданное свойство как обычно:

cityNameProperty.bind(cityNameTF.textProperty());

и изменения свойства text текстового поля изменят cityName в экземпляре MapDTO.

...