6 Manejo de cambios¶
Propiedades¶
Una propiedad en JavaFX es un tipo especial de variable de un objeto JavaFX. Las propiedades JavaFX son usadas para almacenar información de un objeto. Además, las propiedades tienen la capacidad de notificar cambios de sus valores y también permiten hacer asociaciones con propiedades de otros los objetos. Las propiedades deben ser clases que implementen la interfaz ObservableValue
.
ObservableValue
es una interfaz que representa un valor observable, es decir, un valor cuyo cambio puede ser observado por otros objetos. Esta interfaz se encuentra en el paquete javafx.beans.value
y es fundamental para implementar el patrón de diseño Observer/Observable
en el contexto de las propiedades observables.
JavaFX proporciona varias implementaciones de ObservableValue
para diferentes tipos de propiedades, como BooleanProperty
, IntegerProperty
, DoubleProperty
, StringProperty
, etc. Es ampliamente utilizado en JavaFX para sincronizar automáticamente los cambios de estado de los datos con la interfaz de usuario, asegurando que los componentes gráficos reflejen siempre el estado actual de los datos.
A continuación se presentan algunos métodos comunes que se encuentran en la interfaz ObservableValue:
addListener(ChangeListener<? super T> listener)
: Permite registrar unChangeListener
que será notificado cuando el valor observado cambie.removeListener(ChangeListener<? super T> listener)
: Permite eliminar unChangeListener
registrado previamente.getValue()
: Retorna el valor actual delObservableValue
.setValue(T value)
: Cambia el valor de la propiedad al valor dado.
Algunos componentes, como CheckBox
o RadioButton
utilizan estas propiedades internamente. También propiedades como Label
o TextField
las contiene. Para acceder a ellas, como valores observables, se puede acceder a través de los métodos xxxProperty()
donde xxx
es el tipo de dato. Por ejemplo, para acceder al texto observable de un Label
, se accedería a través de textProperty()
.
También es posible asociar propiedades entre sí, de tal forma que cuando se produzca un cambio en alguna propiedad, automáticamente se cambie la propiedad asociada, es decir, cuando dos variables están asociadas, un cambio de una se ve reflejada en la otra. Para asociar una propiedad a otra es necesario utilizar el método bind(ObjectValue<? extends T> property)
de las propiedades. Veamos un ejemplo:
Slider slider = new Slider(0, 1, 0);
ProgressBar bar = new ProgressBar(0);
bar.setMaxWidth(Double.MAX_VALUE);
bar.progressProperty().bind(slider.valueProperty);
En el ejemplo anterior, se está asociando el valor del slider a la barra de progreso, por lo que cuando cambie el valor del slider, también cambiará el valor de la barra de progreso. En este caso, estamos ante una asociación unidireccional, es decir, los cambios de una propiedad se ve reflejada en la otra, pero no al revés. Para que una asociación sea bidireccional es necesario utilizar el método bindDirectional(Property<T> property)
. Por el contrario, se puede desasociar dos propiedades, haciendo uso del método unbind()
para asociaciones unidireccionales y unbindBidirectional(Property<T> other)
para bidireccionales.
Para hacer cualquier objeto en JavaFX como un valor observable, puedes utilizar las clases provistas en el paquete javafx.beans.property
, como SimpleObjectProperty
o ReadOnlyObjectWrapper
. Estas clases permiten envolver un objeto y proporcionar métodos para acceder y modificar ese objeto de manera observable, es decir, permiten detectar cambios en su valor y notificar a los listeners registrados. SimpleObjectProperty
es mutable, es decir, permite lectura y escritura, mientras que ReadOnlyObjectWrapper
es inmutable, es decir, solo permite lectura.
ChangeListener¶
ChangeListener
es una interfaz funcional y genérica que se utiliza para escuchar cambios en un ObservableValue
. Esta interfaz permite detectar y manejar eventos cuando el valor de una propiedad observable cambia. En el caso específico de un CheckBox, podemos utilizar un ChangeListener
para ser notificados cuando el estado seleccionado del CheckBox
cambia.
El método de dicha interfaz es change(ObservableValue<? extends T> observable, T oldValue, T newValue)
, que recibe el objeto observable cuyo valor ha cambiado, el viejo valor y el nuevo valor.
Cuando se registra un ChangeListener
a un ObservableValue
, el método changed
se ejecutará cada vez que el valor del ObservableValue
cambie. Dentro del método changed
, puedes implementar la lógica para manejar y responder al cambio de valor. Por ejemplo, actualización de la interfaz de usuario, procesamiento de datos, o cualquier acción basada en el cambio detectado.
IntegerProperty counter = new SimpleIntegerProperty(0);
counter.addListener(new ChangeListener<Number>() {
@Override
public void changed(ObservableValue<? extends Number> observable, Number oldValue, Number newValue) {
System.out.println("Contador ha cambiado de " + oldValue + " a " + newValue);
}
});
counter.set(1);
counter.set(5);
Colecciones JavaFX¶
En JavaFX, existe el paquete javafx.collections
que reúne una serie de interfaces y clases para las colecciones de JavaFX, entre ellas encontramos:
ObservableList
: Interfaz que representa una lista que permite a los listeners detectar los cambios que producen.ListChangeListener
: Interfaz que recibe las notificaciones de cambios de unObservableList
FXCollections
: Clase de utilidad con métodos estáticos que son copias de los métodos de la clasejava.util.Collections
.ListChangeListener.Change
: Clase que representa un cambio realizado por unObservableList
.
Existe clases e interfaces parecidas para mapas y conjunto observables. Sus nombres son parecidos a lo de las listas observables, pero el lugar de usar List
se usaría Map
o Set
, respectivamente. Por ejemplo, existe la interfaz ObservableMap
para mapas y ObservableSet
para conjuntos.
En el siguiente ejemplo, se observa los cambios desarrollados en una lista:
List<String> list = new ArrayList<String>();
ObservableList<String> observableList = FXCollections.observableList(list);
observableList.addListener(new ListChangeListener(){
@Override
public void onChanged(ListChangeListener.Change change){
System.out.println("Detected change!");
}
});
Hasta ahora, hemos visto algunos componentes donde era necesario indicar los elementos de dicho componente como una lista observable.
Cuando se modifica la lista (se añaden, eliminan o modifican elementos), se generan eventos de cambio que notifican a los listeners sobre los detalles específicos de la modificación.
ObservableList
está diseñada para ser utilizada en conjunto con componentes gráficos de JavaFX, como ListView
, TableView
, ComboBox
, etc., para mantener la sincronización automática entre los datos y la interfaz de usuario.
A continuación se presentan algunos métodos comunes que se encuentran en la interfaz ObservableList
:
addListener(InvalidationListener listener)
: Permite registrar unInvalidationListener
que será notificado cuando la lista se invalide. Esto significa que la lista ha cambiado estructuralmente de alguna manera y puede requerir que se vuelva a consultar.addListener(ListChangeListener<? super E> listener)
: Permite registrar unListChangeListener
que será notificado cuando se realicen cambios estructurales en la lista, como añadir, eliminar o reordenar elementos.removeListener(InvalidationListener listener)
: Permite eliminar unInvalidationListener
registrado previamente.removeListener(ListChangeListener<? super E> listener)
: Permite eliminar unListChangeListener
registrado previamente.addAll(E... elements)
: Añade todos los elementos especificados al final de la lista.removeAll(E... elements)
: Elimina todos los elementos especificados de la lista, si están presentes.clear()
: Elimina todos los elementos de la lista.