JavaFX Binding (sincronizar propiedades)
En el tutorial anterior hablamos de las Propiedades JavaFX, más específicamente el como crearlas y utilizarlas, en este nuevo tutorial veremos como dos propiedades pueden mantener sus valores sincronizados, es decir, si la propiedad A esta enlazada con la propiedad B cualquier cambio en el valor de B se reflejará en A, no funciona al inverso, a esto se le llama: unidirectional binding, si que el enlace sea en doble vía, es decir, deseamos que cualquier cambio de A se refleje en B y un cambio en B se refleje en A necesitamos un bidirectional binding.
Para crear un enlace en una sola vía usamos el método bind()
para crear un enlace en doble vía usaremos bindBidirectional()
y cuando deseemos cortar el enlace utilizaremos los métodos unbind()
o unbindBidirectional()
según corresponda, estos métodos están presentantes en las propiedades JavaFX.
Este es un ejemplo de un unidirectional binding la propiedad progressProperty
del control ProgressBar
esta enlazada con la propiedad valueProperty
del control Slider
, al mover el Slider
se cambia también el ProgressBar
.
Slider slider = new Slider(0, 1, 0);
ProgressBar bar = new ProgressBar(0);
bar.setMaxWidth(Double.MAX_VALUE);
bar.progressProperty().bind(slider.valueProperty());
VBox root = new VBox(slider, bar);
root.setPadding(new Insets(10.0));
root.setSpacing(10.0);
Debemos tener presente que no podemos cambiar la propiedad progressProperty
usando set/setValue
mientras la misma se encuentre enlazada, podemos usar unbind()
para terminar el enlace y luego cambiar la propiedad.
En este segundo ejemplo creamos un enlace en doble vía, usaremos dos controles TextField
, lo que escribimos en el primero se refleja en el segundo, si cambiamos el texto del segundo también cambia el texto del primero.
TextField tf_1 = new TextField();
TextField tf_2 = new TextField();
tf_1.textProperty().bindBidirectional(tf_2.textProperty());
VBox root = new VBox(tf_1, tf_2);
root.setPadding(new Insets(10.0));
root.setSpacing(10.0);
El enlace no esta restringido a propiedades del mismo tipo, veremos un ejemplo donde enlazamos el elemento seleccionado de un ListView<Integer>
al texto de un control Label
.
ListView<Integer> lv = new ListView<>();
lv.getItems().addAll(1, 2, 3, 4, 5);
String txt = "Elemento seleccionado: %d";
Label lbl = new Label();
lbl.textProperty().bind(lv.getSelectionModel()
.selectedItemProperty().asString(txt));
Usamos getSelectionModel().selectedItemProperty()
para acceder a la propiedad que indica cual es el elemento actualmente seleccionado, como este elemento es de tipo Integer
y textProperty()
requiere un String
usamos el método asString()
para convertir la propiedad, este método puede ser usado sin parámetros o indicando una cadena que establece el formato para la conversión.
Los enlaces también pueden ser de tipo numérico, NumberBinding
, estos nos proveen una serie de operaciones aritméticas que podemos aplicar para recalcular el valor de una propiedad antes de sincronizarla, en el siguiente ejemplo creamos un conversor de unidades, sincronizamos las propiedades value del Slider
con text del TextField
, pero antes debemos multiplicar por el correspondiente valor para obtener la conversión.
Slider sliderPies = new Slider(0, 100, 0);
sliderPies.setShowTickMarks(true);
sliderPies.setShowTickLabels(true);
NumberBinding pulgadas = sliderPies.valueProperty().multiply(12);
NumberBinding metros = sliderPies.valueProperty().multiply(.3048);
TextField txtPulgadas = new TextField();
txtPulgadas.textProperty().bind(pulgadas.asString("En pulgadas: %.2f"));
TextField txtMetros = new TextField();
txtMetros.textProperty().bind(metros.asString("En metros: %.2f"));
No solo podemos multiplicar, también tenemos disponible métodos para sumar add()
, restar subtract()
, dividir divide()
, además podemos aplicarlas en combinación para lograr operaciones más complejas, debemos saber que los parámetros de estas operaciones puedes ser un valor constante u otra propiedad siempre que sea del tipo adecuado.
Otro tipo de enlace son los BooleanBinding
que nos permiten sincronizar propiedades de tipo booleano, nuestro ejemplo habilita el botón solo cuando se ha escrito algún texto en ambos controles TextField
.
Label lblNombre = new Label("Nombre");
Label lblContrasena = new Label("Contrasena");
TextField tfNombre = new TextField();
PasswordField tfContrasena = new PasswordField();
Button btnEntrar = new Button("Entrar");
btnEntrar.setMaxWidth(Double.MAX_VALUE);
btnEntrar.disableProperty().bind(
tfNombre.textProperty().isEmpty().or(
tfContrasena.textProperty().isEmpty()));
Al final del fragmento de código veremos textProperty().isEmpty()
esto verifica si la propiedad text está vacía y devuelve un BooleanBinding
luego usamos el método or para aplicar una operación lógica con la propiedad text del otro campo de texto, lo que quiere decir que, si el primer o segundo campo de texto está vacío el botón estará deshabilitado.
Como la propiedad del control Button
llamada disableProperty
es de tipo BooleanProperty
le podemos aplicar el BooleanBinding
.
Existen otras formas de crear enlaces, una es usando la clase Bindings la cual cuenta con aproximadamente 100 métodos estáticos que podemos utilizar para diversos propósitos, otra manera es utilizar la API a bajo nivel, con ella tenemos mas control por lo que podemos realizar operaciones más complejas, estas formas alternativas de crear enlaces las veremos en próximos tutoriales.
Descargar ejemplos en: GitHub Tutoriales JavaFX
Me ha ayudado mucho, esta explicado de una forma clara y sencilla, Muchas gracias.
ResponderEliminarexcelente tutorial, el mejor que he visto hasta ahora
ResponderEliminarEsta muy bien muchas gracias, me gustaría saber como aplicar binding a los CheckBox, Datepicker, entre otros, gracias un saludo
ResponderEliminar