SDK Multiplataforma en C logo

SDK Multiplataforma en C

Data binding

❮ Anterior
Siguiente ❯

El Data Binding es una técnica que nos permite registrar las estructuras o clases del programa con el fin de automatizar ciertas tareas, como la sincronización del modelo de datos con la interfaz de usuario.


Funciones

voiddbind (...)
voiddbind_enum (...)
type*dbind_create (...)
voiddbind_init (...)
voiddbind_remove (...)
voiddbind_destroy (...)
voiddbind_destopt (...)
type*dbind_read (...)
voiddbind_write (...)
voiddbind_default (...)
voiddbind_range (...)
voiddbind_precision (...)
voiddbind_increment (...)
voiddbind_suffix (...)

Entendemos por Data Binding (vinculación de datos o enlace de datos) la posibilidad de sincronizar automáticamente las estructuras del programa con diferentes fuentes de entrada/salida. Partimos del sencillo modelo (Listado 1) que presentamos en Arrays compuesto por un struct y un enum.

Listado 1: Sencillo modelo de datos basado en struct.
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
typedef struct _product_t Product;

typedef enum _type_t
{
    ekCPU,
    ekGPU,
    ekHDD,
    ekSCD
} type_t;

struct _product_t
{
    type_t type;
    String *code;
    String *description;
    Image *image64;
    real32_t price;
};

Lo primero que tenemos que hacer, es registrar este modelo en dbind, una especie de "base de datos" general dentro de nuestra aplicación (Listado 2). Únicamente es necesario realizar este proceso una vez al arrancar el programa. De esta forma se crearán unas tablas internas con la descripción de cada estructura del modelo de datos (Figura 1), quedando el programa preparado para automatizar ciertas tareas al trabajar con objetos de dichas clases.

  • Utiliza dbind para registrar los campos de una estructura.
  • Utiliza dbind_enum para registrar los diferentes valores de tipos enumerados.
  • Listado 2: Registrando el modelo de datos de (Listado 1).
    1
    2
    3
    4
    5
    6
    7
    8
    9
    
    dbind_enum(type_t, ekCPU, "");
    dbind_enum(type_t, ekGPU, "");
    dbind_enum(type_t, ekHDD, "");
    dbind_enum(type_t, ekSCD, "");
    dbind(Product, type_t, type);
    dbind(Product, String*, code);
    dbind(Product, String*, description);
    dbind(Product, Image*, image64);
    dbind(Product, real32_t, price);
    
    Esquema que muestra una estructura de datos y su tabla equivalente.
    Figura 1: Tablas internas creadas por dbind al registrar el modelo de datos.

1. Sincronización con interfaces gráficas

Uno de los usos más extendidos del enlace de datos, es la posibilidad de sincronizar la interfaz gráfica con los objetos que forman el modelo de datos. Este paradigma es conocido como MVVM (Model-View-ViewModel) (Figura 2) y profundizaremos más en él GUI Data binding.

Conexiones entre una interfaz de usuario y los datos que manipula.
Figura 2: Sincronización automática de datos e interfaz.

2. Lectura y escritura de JSON

El análisis sintáctico de scripts JSON también se puede automatizar gracias a dbind (Figura 3). En JSON dispondrás de información detallada de como hacerlo.

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
{
    "code":0,
    "size":80,
    "data":[
    {"id":0,
    "code":"i7-8700K",
    "description":"Intel BX80684I78700K 8th Gen Core i7-8700K Processor",
    type":0,
    "price":374.8899999999999863575794734060764312744140625,
    "image":"cpu_00.jpg",
    "image64":"\/9j\/4AAQSkZJRgABAQ....
    },
    ...
}
Conexiones entre los campos de un objeto y un script JSON.
Figura 3: Data Binding en el análisis de scripts JSON.

3. Serialización con DBind

Como ya vimos en Serialización y Unificar la serialización necesitamos definir funciones de lectura y escritura de objetos para enviarlos o recibirlos a través de streams. Afortunadamente, dbind conoce la composición detallada de cada objeto registrado, por lo que puede acceder a la E/S sin que sea necesario programar explícitamente dichas funciones (Listado 3) (Figura 4).

Listado 3: Serialización de objetos con dbind.
1
2
3
ArrPt(Product) *products = dbind_read(stream, ArrPt(Product));
...
dbind_write(stream, products, ArrPt(Product));
Acceso a las tablas de dbind para serializar objetos.
Figura 4: Lectura/Escritura de objetos mediante dbind.

4. Constructor por defecto

Gracias a dbind también podemos crear objetos inicializados con valores por defecto sin necesidad de crear constructores específicos (Listado 4). También se pueden destruir garantizando la correcta liberación recursiva de la memoria de todos sus campos.

Los valores por defecto al inicializar los campos del objeto son 0 para números, FALSE para booleanos, "" para Strings y contenedores vacíos en el caso de arrays o sets. Si el objeto contiene sub-objetos anidados, estos también serán creados/inicializados de forma recursiva. Estos valores por defecto se pueden cambiar si fuera necesario (Listado 5).


5. Rangos numéricos

Es posible configurar los campos numéricos uint32_t, int8_t, real64_t para acotar los valores aceptados a un determinado rango (Listado 6). dbind se encargará de validar los datos cada vez que lea valores de cualquier origen de datos (GUI, JSON, Streams, etc).


dbind ()

Añade un campo de una estructura/clase a su tabla interna dentro de dbind.

void
dbind(type,
      mtype,
      name);
type

Tipo de la estructura o clase.

mtype

Tipo del campo a registrar.

name

Nombre del campo dentro de la estructura.

Observaciones

Se generarán errores en tiempo de compilación si el campo indicado no pertenece a la estructura. El método también sirve para clases en C++.


dbind_enum ()

Registra un valor tipo enum.

void
dbind_enum(type,
           value,
           const char_t *alias);
type

Tipo del enum.

value

Valor.

alias

Alias para el valor.

Observaciones

dbind_enum(mode_t, ekIMAGE_ANALISYS, "Image Analisys"); utilizará la cadena "Image Analisys" en lugar de "ekIMAGE_ANALISYS" para aquellas operaciones E/S o de interfaz que requieran mostrar los literales del enumerado. Por ejemplo, para rellenar los campos de un PopUp vinculado con un campo de datos.


dbind_create ()

Crea un objeto de tipo registrado, inicializando sus campos con los valores por defecto.

type*
dbind_create(type);
type

Tipo de objeto.

Retorna

Objeto recién creado o NULL si dbind no reconoce el tipo de dato.


dbind_init ()

Inicializa los campos de un objeto de tipo registrado con los valores por defecto.

void
dbind_init(type *obj,
           type);
obj

Objeto cuya memoria ha sido reservada, pero no inicializada.

type

Tipo de objeto.


dbind_remove ()

Destruye la memoria reservada por los campos de un objeto de tipo registrado, pero no destruye el objeto en sí.

void
dbind_remove(type *obj,
             type);
obj

Objeto.

type

Tipo de objeto.


dbind_destroy ()

Destruye un objeto de tipo registrado. La memoria asignada a los campos y sub-objetos también será liberada de forma recursiva.

void
dbind_destroy(type **obj,
              type);
obj

Objeto. Será puesto a NULL tras la destrucción.

type

Tipo de objeto.


dbind_destopt ()

Destructor opcional. Igual que dbind_destroy, pero aceptando que el objeto sea NULL.

void
dbind_destopt(type **obj,
              type);
obj

Objeto a destruir.

type

Tipo de objeto.


dbind_read ()

Crea un objeto de tipo registrado a partir de los datos leídos desde un stream.

type*
dbind_read(Stream *stm,
           type);
stm

Stream de lectura.

type

Tipo del objeto a leer.

Retorna

Objeto recién creado o NULL si ha habido algún error.


dbind_write ()

Escribe el contenido de un objeto de tipo registrado en un stream de escritura.

void
dbind_write(Stream *stm,
            const type *data,
            type);
stm

Stream de escritura.

data

Objeto a escribir.

type

Tipo del objeto a escribir.


dbind_default ()

Establece el valor por defecto de un campo.

void
dbind_default(type,
              mtype,
              name,
              mtype value);
type

Tipo de la estructura o clase.

mtype

Tipo del campo.

name

Nombre del campo dentro de la estructura.

value

Valor por defecto a partir de ahora.


dbind_range ()

Establece el valor máximo y mínimo en campos numéricos.

void
dbind_range(type,
            mtype,
            name,
            mtype min,
            mtype max);
type

Tipo de la estructura o clase.

mtype

Tipo del campo.

name

Nombre del campo dentro de la estructura.

min

Valor mínimo.

max

Valor máximo.

Observaciones

Dará error si se utiliza en campos no numéricos.


dbind_precision ()

Establece el salto entre dos valores numéricos consecutivos.

void
dbind_precision(type,
                mtype,
                name,
                mtype prec);
type

Tipo de la estructura o clase.

mtype

Tipo del campo.

name

Nombre del campo dentro de la estructura.

prec

Precisión (p.e. .05f en valores real32_t).

Observaciones

Dará error si se utiliza en campos no numéricos.


dbind_increment ()

Establece el incremento de un valor numérico al pulsar en un control UpDown.

void
dbind_increment(type,
                mtype,
                name,
                mtype incr);
type

Tipo de la estructura o clase.

mtype

Tipo del campo.

name

Nombre del campo dentro de la estructura.

incr

Incremento.

Observaciones

Dará error si se utiliza en campos no numéricos.


dbind_suffix ()

Establece un sufijo que será añadido al valor numérico al convertirlo a texto.

void
dbind_suffix(type,
             mtype,
             name,
             const char_t *suffix);
type

Tipo de la estructura o clase.

mtype

Tipo del campo.

name

Nombre del campo dentro de la estructura.

suffix

Sufijo.

Observaciones

Dará error si se utiliza en campos no numéricos.

❮ Anterior
Siguiente ❯