JavaFX-свойства: Многие атрибуты UI-элементов представлены как объекты-свойства (например, StringProperty textProperty у Label). Они поддерживают наблюдение и привязку.
Однонаправленная привязка: значение одного свойства автоматически обновляется при изменении другого. Пример: label.textProperty().bind(slider.valueProperty().asString("%.0f")) – текст метки всегда равен значению слайдера.
Двунаправленная привязка: два свойства синхронизируются между собой (изменение любого обновляет другое). Устанавливается методом bindBidirectional().
Преимущества: привязки сокращают шаблонный код обновления UI, обеспечивают согласованность данных и интерфейса, упрощают реализацию MVC (View автоматически отражает изменения в Model).
Одно из наиболее мощных средств JavaFX – это свойства и привязки. Свойство (
Property) в JavaFX – это объект-обёртка вокруг некоторого значения, например, строки или числа, который позволяет наблюдателям подписаться на изменения этого значения. Всякий раз, когда значение свойства меняется, фреймворк может уведомлять слушателей или обновлять связанные свойства.
Простейший пример: у класса Label есть метод textProperty() возвращающий объект StringProperty. Допустим, у нас есть слайдер:
Label label = new Label();
label.textProperty().bind( slider.valueProperty().asString("%.0f") );
Здесь мы привязываем текст метки к значению слайдера. Метод
asString("%.0f") превращает числовое значение слайдера в строку по заданному формату (без десятичной части). После этой привязки нам больше не нужно вручную обновлять текст метки – при любом перемещении ползунка (и изменении его valueProperty) JavaFX автоматически пересчитает связанное выражение и установит новый текст метки Таким образом, UI всегда синхронизирован с данными.
Привязки бывают однонаправленные (unidirectional) – как в примере: label.textProperty() слушает slider.valueProperty(), но не наоборот. Бывают и двунаправленные (bidirectional) – когда два свойства должны одновременно обновлять друг друга. Например, если есть текстовое поле TextField для ввода числа и тот же слайдер, можно их связать двунаправленно, чтобы изменение одного сразу меняло другое:
textField.textProperty().bindBidirectional( slider.valueProperty(), new NumberStringConverter() );
Здесь используется вспомогательный класс
NumberStringConverter для преобразования строки в число и обратно. После этого, если пользователь введёт новое значение в текстовое поле – слайдер двинется к этому значению, и наоборот, перетаскивание слайдера обновит текст.
Привязке поддаются не только UI-элементы. Вы можете создать свои свойства в моделях данных (например, property в классе Person для имени) и привязать их к контролам. Это реализует принцип MVC: модель изменяется – представление (UI) автоматически отражает новые данные. Или наоборот – пользователь меняет поле, а property в модели меняется через bidirectional-binding.
С технической стороны, JavaFX-свойства реализуют интерфейсы Observable и ObservableValue. Можно добавлять слушателей (InvalidationListener или ChangeListener) к любому свойству, чтобы выполнить код при его изменении. Но чаще удобнее использовать декларативные привязки, как выше – они сразу описывают, кто от кого зависит, и избавляют от написания обработчиков изменений.
Практический пример привязки: предположим, у нас есть CheckBox "Показать детали" и некая панель detailsPane, которую надо скрывать/показывать в зависимости от состояния чекбокса. Вместо того чтобы в обработчике писать detailsPane.setVisible(checkBox.isSelected());, можно сделать: detailsPane.visibleProperty().bind(checkBox.selectedProperty());. Одной строкой мы установили, что свойство видимости панели напрямую связано с состоянием чекбокса. Такая декларативность улучшает читаемость – видно, что должно быть связано, без описания механики.
Стоит отметить, что привязки исполняются эффективным образом – они ленивы (не пересчитываются, пока значение не понадобится), и само обновление происходит на том потоке, где изменилось исходное свойство (в UI потоке для UI-свойств). Если менять модель из фонового потока, свойства тоже нужно обновлять через Platform.runLater, иначе нарушение потока.
Свойства JavaFX также интегрируются с Java Beans (есть методы getValue()/setValue() и специальные PropertyAdapter-ы), что позволяет, например, привязывать их к Swing или Beans-свойствам, но в современных приложениях это редко нужно. Главное – правильно использовать привязки внутри JavaFX, чтобы избежать избыточного кода и обеспечить согласованность данных и интерфейса.
