JFace controles y binding

De Uqbar wiki

Nota: el objetivo de esta página es comentar cómo se produce el binding entre controles de SWT/JFace y atributos de dominio. Si desea documentación para programar interfaces de usuario puede consultar la página oficial de SWT y el wiki de JFace

Cómo se implementa el binding en JFace

A través de la clase DataBindingContext que conoce a ambos observers: los interesados en los cambios del modelo (BeansObservables) pero también al modelo le interesa los cambios que hace el usuario a través de la vista (SWTObservables).

Ejemplo: si queremos tener binding bidireccional entre el atributo nombre de un Socio y el control textbox de la pantalla de actualización de un socio

Control Textbox

En SWT el textbox está representado por la clase org.eclipse.swt.widgets.Text

Podemos bindear la propiedad text de un control textbox contra un atributo String de un modelo de la siguiente manera

new DataBindingContext().bindValue(
    SWTObservables.observeText(controlTextBoxEnCuestion, SWT.FocusOut), 
    BeansObservables.observeValue(objetoModelo, propiedadDelModeloContraElQueSeBindea), 
    null, 
    null);

donde controlTextBoxEnCuestion es de tipo Text, objetoModelo es cualquier Object y propiedadDelModeloContraElQueSeBindea es un String.

Otras propiedades que admiten binding bidireccional:

Ejemplo: queremos permitir cambiar el nombre a un socio solamente si está activo. El socio define como interfaz setNombre/getNombre y un isActivo(), no importa cómo se implementa. Entonces para bindear la propiedad Editable del textbox que ingresa el nombre (llamado textNombre) debemos escribir lo siguiente:

new DataBindingContext().bindValue(
    SWTObservables.observeEditable(textNombre), 
    BeansObservables.observeValue(socio, "activo"), 
    null, 
    null);

Nótese que no necesariamente la “propiedad” del modelo tiene que ser un atributo (variable de instancia) del objeto modelo. En nuestro caso el estar activo podría no ser un getter booleano sino un atributo calculado dinámicamente. Lo que hace JFace es recuperar el valor del método getActivo() o isActivo() para el objeto socio (a través de Reflection) y asociarlo a la propiedad editable del control (lo que devuelva el método getActivo() debe ser un booleano).

Mirando la clase SWTObservables podemos ver todas las propiedades que el framework en cuestión nos permite vincular.

Las siguientes propiedades no tienen binding bidireccional con un atributo del modelo. No obstante, podemos modificar sus valores al cargar el formulario o ante cualquier otro evento que el usuario o la pantalla dispare:

Control Checkbox

En SWT el checkbox está representado por la clase org.eclipse.swt.widgets.Button pasándole el parámetro SWT.CHECK al constructor.

Se puede bindear la propiedad SELECTION contra un atributo boolean de un modelo:

new DataBindingContext().bindValue(
    SWTObservables.observeSelection(controlCheckBoxEnCuestion), 
    BeansObservables.observeValue(objetoModelo, atributoBooleanDelModeloContraElQueSeBindea), 
    null, 
    null);

También se puede bindear las propiedades visible, font, foreground y background, entre otras. No tiene sentido bindear la propiedad text, hacerlo resulta en error.

Control Combo

En SWT el combo está representado por la clase org.eclipse.swt.widgets.Combo

Se agregan elementos al combo:

Como se desprende de la interfaz de cada uno de los métodos

Para conocer cuál es el elemento seleccionado del combo enviamos el mensaje getSelectionIndex(), que devuelve un int. Vemos el javadoc:

/**
 * 
 * Returns the zero-relative index of the item which is currently selected in the
 * receiver's list, or -1 if no item is selected.
 *
 */
public int getSelectionIndex() 

Tener el selectionIndex como un entero refuerza la idea de que el orden en el combo es importante, si tengo los elementos en un Set no me serviría el selectionIndex.

El binding relaciona un String con la propiedad selection del combo cuando el usuario modifica el elemento elegido.

Ejemplo: queremos definir un combo cuyos elementos son la lista de socios de un videoclub. El código es el siguiente

Combo comboSocios = new Combo(formulario, SWT.LEFT | SWT.BORDER | SWT.SINGLE);
comboSocios.setLayoutData(new GridData(150, SWT.DEFAULT));
for (Socio socio : this.getSocios()) {
    comboSocios.add(socio.getNombreCompleto());
}
new DataBindingContext()
    .bindValue(SWTObservables.observeSelection(comboSocios), 
               BeansObservables.observeValueEditarSocioModel, socioSeleccionado), 
               null,
               null);

El binding no lo podemos hacer contra un socio en particular, necesitamos trabajar con un model que tenga comportamiento adicional. El EditarSocioModel define el método setSocioSeleccionado de la siguiente manera:

public void setSocioSeleccionado(String nombreCompletoSocio) {
`    ...
}

Aquí entonces hay que convertir el nombre del socio (un String) al objeto Socio en cuestión si queremos enviarle algún mensaje.

Control Grilla

En SWT la grilla se representa con la clase org.eclipse.swt.widgets.Table

Control Botón

En SWT la grilla se representa con la clase org.eclipse.swt.widgets.Button pasándole el parámetro SWT.PUSH al constructor.

El botón tiene listeners, cuando el usuario presiona el botón se dispara la notificación del botón apretado a cada listener. Nosotros escribimos el código no en el botón, sino en el listener.

Ejemplo:

Button botonAceptar = new Button(formulario, SWT.PUSH);
botonAceptar.setText("Aceptar");
botonAceptar.addSelectionListener(
    new SelectionListener() {
        @Override
        public void widgetSelected(SelectionEvent e) {
            ... <-- ACA ESCRIBIMOS EL CODIGO DEL BOTON -->
        }
        @Override
        public void widgetDefaultSelected(SelectionEvent e) {
            this.widgetSelected(e);
        }
         
    );

Las propiedades más interesantes de bindear son enabled (si el botón está habilitado) y visible (si está visible).

Campos calculados

Podemos subclasificar la clase ComputedValue para vincular cualquier expresión que deseemos: sólo tenemos que redefinir el método

protected Object calculate()

Pueden verse los siguientes ejemplos > ver ComputedValue

Links relacionados

Latest update on July 17, 2017 by GitHub