Localizador de objetos

Cada día intentamos que nuestras aplicaciones en Velneo sean más dinámicas y personalizables. Para facilitar la tarea de seleccionar objetos en tiempo de ejecución os presentamos el componente “Localizador de objetos“.

Localizador de Objetos

Requisitos del “Localizador de Objetos”

Para especificar los requisitos del objeto a seleccionar podemos parametrizar el localizador con el origen, destino, tipo de objeto, proyecto donde buscar…

Ejecutar localizador de objetos

Origen

IO_TYPE_IN (-1) cualquier, (0) sin origen, (1) registro, (2) lista
TBL_ID_REF_IN Referencia de la tabla de entrada (velneo_verp_dat/VTA_FAC_G)

Destino

IO_TYPE_OUT (-1) cualquier, (0) sin origen, (1) registro, (2) lista
TBL_ID_REF_OUT Referencia de la tabla de entrada (velneo_verp_dat/VTA_FAC_G)

Tipo de objeto

OBJ_TYPE Ver clase VObjectInfo VObjectInfo.TypeTable, VObjectInfo.TypeNone, VObjectInfo.TypeForm...

Alias o tipo de proyecto

PRJ_ID Alias del proyecto (velneo_verp_dat)
PRJ_TYPE Ver clase VProjectInfo VProjectInfo.TypeDat, VProjectInfo.TypeApp, VObjectInfo.TypeForm...

 

En el .vin que adjuntamos se incluyen más ejemplos de parametrización.

DEMO – Opciones del localizador objetos

Posibles mejoras del “Localizar de Objetos”

Entre las posibles modificaciones y mejoras para este componente se nos han ocurrido las siguientes:

  • Especificar varios tipos de objeto a seleccionar, por ejemplo, si queremos seleccionar un visor de lista así podremos elegir indistintamente entre rejillas, casilleros…
  • Prefijo/Sufijo: es muy común usar prefijos o sufijos para definir módulos dentro de un proyecto, por ejemplo, vERP utiliza los sufijos “C”, “G”, “M” y “W”, podrían añadirse como opciones al filtro.

¿Te atreves con ellas?

¿A qué esperas para descargarte el “Localizador de Objetos”del Profesor vBacterio?

Pruébalo y déjame un comentario mas abajo

La entrada Localizador de objetos aparece primero en AyudaVelneo.

Localizador de objetos

Cada día intentamos que nuestras aplicaciones en Velneo sean más dinámicas y personalizables. Para facilitar la tarea de seleccionar objetos en tiempo de ejecución os presentamos el componente “Localizador de objetos“.

Localizador de Objetos

Requisitos del “Localizador de Objetos”

Para especificar los requisitos del objeto a seleccionar podemos parametrizar el localizador con el origen, destino, tipo de objeto, proyecto donde buscar…

Ejecutar localizador de objetos

Origen

IO_TYPE_IN (-1) cualquier, (0) sin origen, (1) registro, (2) lista
TBL_ID_REF_IN Referencia de la tabla de entrada (velneo_verp_dat/VTA_FAC_G)

Destino

IO_TYPE_OUT (-1) cualquier, (0) sin origen, (1) registro, (2) lista
TBL_ID_REF_OUT Referencia de la tabla de entrada (velneo_verp_dat/VTA_FAC_G)

Tipo de objeto

OBJ_TYPE Ver clase VObjectInfo VObjectInfo.TypeTable, VObjectInfo.TypeNone, VObjectInfo.TypeForm...

Alias o tipo de proyecto

PRJ_ID Alias del proyecto (velneo_verp_dat)
PRJ_TYPE Ver clase VProjectInfo VProjectInfo.TypeDat, VProjectInfo.TypeApp, VObjectInfo.TypeForm...

 

En el .vin que adjuntamos se incluyen más ejemplos de parametrización.

DEMO – Opciones del localizador objetos

Posibles mejoras del “Localizar de Objetos”

Entre las posibles modificaciones y mejoras para este componente se nos han ocurrido las siguientes:

  • Especificar varios tipos de objeto a seleccionar, por ejemplo, si queremos seleccionar un visor de lista así podremos elegir indistintamente entre rejillas, casilleros…
  • Prefijo/Sufijo: es muy común usar prefijos o sufijos para definir módulos dentro de un proyecto, por ejemplo, vERP utiliza los sufijos “C”, “G”, “M” y “W”, podrían añadirse como opciones al filtro.

¿Te atreves con ellas?

¿A qué esperas para descargarte el “Localizador de Objetos”del Profesor vBacterio?

Pruébalo y déjame un comentario mas abajo

La entrada Localizador de objetos aparece primero en AyudaVelneo.

Postal Navideña 2017. El “making of”

Por tercer año he publicado en el foro una postal navideña realizada con Velneo en la que, además de felicitar las fiestas, pongo en práctica mis conocimientos en aquellos aspectos que pueden dar cierto dinamismo gráfico a nuestras aplicaciones.

Aprovecho para hacer un llamamiento a todos los que lean este artículo para que no dejen morir el foro de Velneo. Creo que es la mejor herramienta que tenemos para dejar nuestro conocimiento grabado y con acceso inmediato para los nuevos discípulos de Velneo.

Este año tocaba desear felices fiestas empleando uno de los objetos largamente esperado por los programadores, el objeto nativo Gráfico.

Los señores de Velneo nos vienen negando desde hace años la disponibilidad de un objeto nativo Canvas que permita aportar a nuestras aplicaciones un punto de libertad a la hora de mostrar elementos gráficos. En su defecto debemos usar el Visor html o QML tal como vimos en la primera y segunda postal navideña respectivamente. Estas soluciones alternativas están muy bien, pero nos encontramos con problemas de rendimiento y multiplataforma, sin contar que debemos aprender lenguajes y técnicas de programación muy poco LifeIsSoft.

Como ya he dicho, este año había que hacer algo con el objeto Gráfico. Este nuevo objeto es el resultado de incorporar a Velneo el módulo QtCharts de Qt, lo que nos permite crear gráficos empresariales tanto en su modalidad de Widget nativo o en su modalidad de Tipo QML (con import QtCharts 2.x).

Teniendo en cuenta que el objeto Gráfico es en realidad un objeto Canvas al que se ha dado una funcionalidad específica, veamos como podemos usarlo para otros menesteres que espero te sorprendan.

Objetivo de este año: Postal navideña con gráficos nativos.

Este año había que mostrar algo dinámico usando el Gráfico en su forma nativa.

El elemento dinámico debía ser una frase de felicitación que contuviera el nombre del Usuario conectado y además hubiera un desplazamiento horizontal a través de la pantalla. Lo más parecido es un Rótulo de leds que vemos habitualmente en las estaciones de autobús o tren para informar de diferentes eventos.

El Rótulo led debe tener los siguientes elementos dinámicos:

  • La frase o mensaje de felicitación es configurable y debe contener el nombre del usuario conectado
  • El Rótulo desplaza horizontalmente la frase de derecha a izquierda y de forma cíclica
  • Los leds luminosos podrán variar de color o de brillo

Diseño del Rótulo LED para mostrar Mensajes

¿Qué tiene que ver un Rótulo led con un objeto Gráfico de Velneo? En realidad mucho.

Un Rótulo led no es más que una matrix de puntos de luz que podemos programar accediendo a ellos mediante sus coordenadas x,y. Por lo tanto, si disponemos de la posibilidad de crear gráficos XY, ya lo tenemos casi hecho. Nos faltará añadir el desplazamiento horizontal y el cambio de color.

Un Gráfico nativo de Velneo al igual que una Rejilla necesita una Lista como entrada para poder representar los datos correspondientes. El Gráfico, por lo tanto, se insertará siempre en los formularios como un control Vista de datos con el correspondiente Proceso que alimenta la Lista de datos a mostrar en el gráfico. Esta característica de Velneo es muy potente y lifeifsoft, ahorrándonos muchas líneas de código, pero también es su talón de aquiles en entornos de redes lentas como Internet.

En Velneo el tipo de gráfico se determina con la propiedad Tipo serie del subobjeto Serie. Para representar un gráfico XY debemos insertar en el Gráfico un subobjeto Serie de tipo Puntos. Los puntos del gráfico se muestran mediante las 2 coordenadas X,Y de los ejes horizontal y vertical respectivamente.

En realidad lo que vamos a hacer es usar el Gráfico nativo como un control Canvas mediante la gestión de coordenadas XY.

Diseño de los caracteres del MENSAJE PARA EL RÓTULO

Para poder construir una frase de forma dinámica debemos disponer del diseño de todos los caracteres posibles en formato de matrix X,Y.

Establecemos una matrix de 5×7 puntos para representar los caracteres.

Construimos una tabla LETRAS_LED con 2 campos, uno con el carácter a representar y otro con una cadena de longitud 7 caracteres con valores posibles de espacio y 1. El espacio indica led apagado y 1 indica led encendido.

En la imagen siguiente se muestran las matrices de las letras A, B, C y D. Cada línea es un registro de la tabla y hay 6 registros por letra, 5 registros de la matrix más 1 de separación entre letras.

La carga de la tabla LETRAS_LED se realiza una sola vez en el ON_INIT_SERVER.

Lista de puntos X,Y de la Vista de datos del Gráfico

Para alimentar la Vista de datos del Gráfico XY necesitamos una tabla con las coordenadas XY ordenadas por el eje X. Estas coordenadas XY serán las que se corresponden con los leds iluminados del Rótulo.

Cada registro de la tabla LETRAS_LED nos proporciona un valor X y hasta 7 valores Y correspondientes a las posiciones de la cadena cuyos valores sean 1.

Por ejemplo la letra C tiene los siguientes valores X,Y que forman la matriz de leds en el rótulo:

eje Y
|               2,7  3,7  4,7
|        1,6                       5,6
|        1,5
|        1,4
|        1,3
|        1,2                       5,2
|               2,1  3,1  4,1
|_____________________ eje X

Necesitamos un proceso PRO_ROT_FRASE_3P que nos devuelva desde la tabla LETRAS_LED las coordenadas de cada una de las letras de la frase que vamos a mostrar en el Rótulo.

Al principio se pensó en rellenar con las coordenadas una tabla en memoria en primer plano, pero lamentablemente en cloud eso es inviable.

Velneo debería revisar el funcionamiento de las tablas en memoria para que en local fuera optativo el crear transacción en el servidor. Esto abriría una multitud de posibilidades en aplicaciones en cloud que necesitan generar listas personalizadas de datos temporales para alimentar objetos de Interfaz como por ejemplo Informes o Gráficos.

De momento se ha optado por una solución más óptima. Ejecutamos en tercer plano el proceso PRO_ROT_FRASE_3P para rellenar la tabla en disco  GRAFICO_XY_3P con las coordenadas de la frase que se mostrará en el Rótulo. Rellenar la tabla en tercer plano y cargar la Lista es mucho más rápido que hacerlo con una tabla local en memoria.

Rem PROCESO PRO_ROT_FRASE_3P
Rem ( Recibe la Frase y el Nombre para identificar las coordenadas en la Tabla )
Rem ( Insertamos NOMBRE, convertimos a mayúsculas, quitamos acentos y sustituimos los espacios por _ )
Set ( _CFRASE, replaceString(removeAccents(toUpper(replaceString(_CFRASE, "[[NOMBRE]]", _CNOMBRE))), " ", "_") )
Libre
Rem ( Rellenamos la Tabla del Gráfico XY desde la tabla LETRAS_LEDS )
For ( NLETRA, 0, NLETRA < len(_CFRASE), 1 )
        Set ( CLETRA, mid(_CFRASE, NLETRA, 1) )
        Rem ( Carga los registros que componen la Letra )
        Cargar lista ( LETRAS_LED@0PS_Navidad_dat, NAME, CLETRA, , , )
                Recorrer lista solo lectura
                        Set ( CLINEA, #LEDS )
                        Set ( NCON_X, NCON_X + 1 )
                        If ( ! isEmpty(CLINEA) )
                                For ( N, 0, N < len(CLINEA), 1 )
                                        If ( mid(CLINEA, N, 1) = "1" )
                                                Crear nueva ficha en memoria ( hGraf, GRAFICO_XY_3P@0PS_Navidad_dat )
                                                        Modificar campo ( NAME, _CNOMBRE )
                                                        Modificar campo ( VALOR_X, NCON_X )
                                                        Modificar campo ( VALOR_Y, N+1 )
                                                        Modificar campo ( TIPO, "M" )
                                                Alta de ficha ( hGraf )
                                                        Libre

Configuración del objeto Gráfico XY (tipo Puntos)

Una vez que ya tenemos diseñado el procedimiento de obtención de las coordenadas de la frase a mostrar en el Rótulo, ya podemos configurar el objeto Gráfico nativo de Velneo GRF_ROTULO_LEDS.

No seleccionamos ningún Tema. Desactivamos la Animación y Menú de contexto y ajustamos los márgenes para aprovechar el espacio de los ejes ya que no los vamos a mostrar. Se puede ocultar el Título si ponemos a cero el canal Alfa del Color.

Añadimos la Serie ROTULO de Tipo Puntos. El Eje X (Categoría) se rellena con el campo #VALOR_X y el Eje Y (Valor) con el campo #VALOR_Y. El Tipo de categoría (coordenadas X) es Numérico y ocultamos las Etiquetas de los valores X,Y. El color de la serie lo determina la variable local CCOLOR que usaremos para atenuar y aumentar el brillo de los leds.

Añadimos un subobjeto Eje de Tipo Eje categorías EJE_X. El Tipo de categoría Numérico, sin Título, sin Etiquetas y sin Línea. Los valores Mínimo y Máximo se determinan mediante las variables locales NEJEX_INI y NEJEX_FIN que como veremos luego son las que desencadenan el refresco del gráfico.

Añadimos un subobjeto Eje de Tipo Eje valores EJE_Y. Sin Título, sin Etiquetas y sin Línea. Los valores Mínimo y Máximo se ajustan manualmente para conseguir una altura correcta del Rótulo.

El diseñador nos muestra el siguiente gráfico. Los círculos representan las coordenadas X,Y de los leds.

Echamos en falta poder cambiar el tamaño de los Puntos para ajustar el tamaño del Rótulo (un despiste tonto del equipo de desarrollo). En la versión QML existe la propiedad markerSize y también se puede cambiar la forma con la propiedad markerShape.

Formulario con el Rótulo del mensaje

Ahora diseñemos un Formulario en el que podamos integrar toda la funcionalidad de este ejercicio.



    • En la parte superior introducimos la frase que deseamos mostrar en el Rótulo.
      El botón <Actualizar> ejecuta el proceso PRO_ROT_FRASE_3P y Recalcula la Vista de datos para obtener las coordenadas XY de la nueva Frase.
    • La Vista de datos GRF_ROTULO con el Gráfico XY (o de Puntos) debe tener una altura fija de 210px.
      Esto es debido a que los caracteres tienen una altura mínima limitada a 7 leds de tamaño fijo (ya que como hemos visto no disponemos de la propiedad markerSize).
      La anchura de los caracteres también debe ser fija y se ha establecido en 110px.
    • El control RUEDA desplaza en los dos sentidos la Frase dentro del Rótulo.
      En ambos lados de la Rueda se muestran las coordenadas del Eje X de la parte de la Frase NEJEX_VENTANA que aparece en el Rótulo .
      Estos valores son NEJEX_INI y NEJEX_INI + NEJEX_VENTANA que se corresponden con las propiedades NEJEX_INI y NEJEX_FIN del Gráfico.
      La Rueda cambia el valor de NEJEX_INI y mediante el manejador RESIZE_JS se calcula NEJEX_VENTANA.
      El siguiente proceso javascript es el más importante desde el punto de vista gráfico, porque permite mantener el ancho fijo de los caracteres cuando redimensionamos la Ventana en los equipos de escritorio o giramos la pantalla en los dispositivos móviles.
// Manejador RESIZE_JS 
// Tenemos que mantener la anchura de los caracteres fija aunque cambie el ancho del Rótulo
// Ancho del Rótulo
var nAnchoRotulo = theRoot.dataView().control("GRF_ROTULO").width
// Los caracteres deben tener un ancho en pixeles determinado para que sean legibles (110px)
// Calculamos entonces el Nº de caracteres que entran en el Rótulo
var nNumLetras = nAnchoRotulo / 110
// Calculamos también el valor X máximo a mostrar (el que está a la derecha de la rueda)
var nEjeX_Fin = nNumLetras * 6  // Cada letra son 6 puntos X
theRoot.setVar("NEJEX_VENTANA", Math.round(nEjeX_Fin))
theMainWindow.showMessageStatusBar("Ancho: " + theMainWindow.width() + "px", 0)
    • El manejador del evento RESIZE de la Vista de datos también recalcula los valores NEJEX_INI y NEJEX_VENTANA para reposicionar la Frase en el Rótulo.
    • El botón CMD_PLAY  pone en marcha el Timer del Formulario (otra ausencia imperdonable es el evento Timer en el objeto Gráfico nativo).
      El manejador TIMER incrementa el valor de NEJEX_INI para desplazar la Frase de derecha a izquierda dentro del Rótulo.
      También cambia el color de los Leds actualizando la propiedad CCOLOR del Gráfico.
    • Tanto manualmente, como a través del Timer o redimensionando el formulario, tan solo necesitamos actualizar las propiedades NEJEX_INI y NEJEX_FIN del Gráfico XY para desplazar la Frase.

Hagamos un Reloj con nuestro Gráfico XY

En un Reloj Digital tenemos siempre un texto de ancho fijo (8 caracteres) y solo necesitamos un Timer de 1 segundo para refrescar la Hora actual.



    • Para el reloj digital lo que hacemos es crear en la tabla de disco GRAFICO_XY_3P las coordenadas de todas las posibles horas del día, desde las 00:00:00 hasta las 23:59:59. Este proceso PRO_RELOJ_CARGAR solo debe ejecutarse una vez y por eso lo ejecutamos en el ON_INIT_SERVER.
    • En el arranque de la aplicación rellenamos mediante un Tubo de Lista la tabla en memoria RELOJ_XY_MEM con todas las coordenadas posibles del Reloj digital.
    • En cada evento TIMER la Frase del Rótulo será currentTime() y esta vez construimos hh:mm:ss de forma dinámica desde la tabla en memoria. La variable global APP_RELOJ_SEGUNDOS determina si se muestran los segundos o no. En el caso de que no se muestren los segundos hacemos que el separador de minutos se encienda y apague cada segundo.
Rem ( Proceso PRO_RELOJ para la Vista de datos del Reloj digital)

Rem ( Obtenemos las coordenadas XY de la Hora actual desde la Tabla en memoria )
Set ( CHORA, timeToString(currentTime(), "hhmmss") )

Rem ( DECENAS DE HORA )
Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "DECENA_HORA_" + mid(CHORA, 0, 1), , ,)
        Añadir lista a la salida
Rem ( UNIDADES DE HORA )
Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "UNIDAD_HORA_" + mid(CHORA, 1, 1), , ,)
        Añadir lista a la salida
If ( $APP_RELOJ_SEGUNDOS@0PS_Rotulo_LED_dat.dat | ((second(currentTime()) % 2) = 0) )
        Rem ( SEPARADOR DE MINUTOS )
        Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "SEP_MINUTOS", , , )
                Añadir lista a la salida
Rem ( DECENAS DE MINUTOS )
Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "DECENA_MINUTO_" + mid(CHORA, 2, 1), , , )
        Añadir lista a la salida
Rem ( UNIDADES DE MINUTOS )
Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "UNIDAD_MINUTO_" + mid(CHORA, 3, 1), , , )
        Añadir lista a la salida
If ( $APP_RELOJ_SEGUNDOS@0PS_Rotulo_LED_dat.dat )
        Rem ( SEPARADOR DE SEGUNDOS )
        Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "SEP_SEGUNDOS", , , )
                Añadir lista a la salida
        Rem ( DECENAS DE SEGUNDOS )
        Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "DECENA_SEGUNDO_" + mid(CHORA, 4, 1), , , )
                Añadir lista a la salida
        Rem ( UNIDADES DE SEGUNDOS )
        Cargar lista ( RELOJ_XY_MEM@0PS_Rotulo_LED_dat, NAME, "UNIDAD_SEGUNDO_" + mid(CHORA, 5, 1), , , )
                Añadir lista a la salida
        Libre
    • El manejador del evento RESIZE ocultará los segundos cuando el ancho del Rótulo muestre menos de 28 coordenadas (4 caracteres x 6 + 4 del separador).

Conclusiones

Con estos 2 ejercicios hemos comprobado que, sin quererlo, Velneo nos ha proporcionado un objeto Canvas nativo para realizar pequeños retos que necesitan algo de dinamismo y potencia gráfica.

Que el objeto Gráfico nativo sea una Vista de datos es por un lado una gran ventaja LifeIsSoft, pero por otro es un handicap en redes lentas debido a la dependencia de Velneo con el hilo de conexión con del vServer, sobre todo en tablas temporales o en memoria.

El uso de Timers en el hilo principal es otro problema con Velneo debido a su bajo rendimiento gráfico. Estos ejercicios en equipos de escritorio se ejecutan con cierta agilidad pero en dispositivos móviles la experiencia gráfica deja mucho que desear. En el evento ON_HIDE de los formularios de ambos ejercicios ejecuto un stopTimer para que no perjudique un formulario en el otro.

En cualquier caso que estos ejercicios os sirvan para aprender sobre las posibilidades de los objetos de Velneo y al mismo tiempo divertirnos con ello. También una forma de hacer ver a los desarrolladores de Velneo las posibilidades que daría un objeto nativo Canvas, junto con tablas en memoria locales y no dependientes del gestor de transacciones.

Podéis probar el ejercicio en el Cloud en la url habitual vatp://pruebas:pruebas@c6.velneo.com:16400/0PS_Rotulo_LED_iapp. En principio es funcional en todas las plataformas.

Finalmente he preparado la versión QML para comparar. En principio podemos pensar que va a ser mucho más ágil el funcionamiento porque tendremos los Timers aislados y los modelos de datos pueden estar totalmente desconectados del servidor. He usado un modelo de datos procedente de un string json.

En los ejercicios del Cloud vatp://pruebas:pruebas@c6.velneo.com:16400/0PS_Varios_iapp tenéis también el código QML (rama Tipos QML de QtChart/Rótulo LEDS – TabView).
Es un buen ejercicio para probar algunos objetos QML interesantes para construir interfaces en dispositivos móviles.

 

Si te ha gustado el post, no dudes en compartirlo por tus redes sociales.

Además podéis dejar un comentario contándome vuestra experiencia usando los Gráficos nativos y vuestros avances con QML.

 

La entrada Postal Navideña 2017. El “making of” aparece primero en AyudaVelneo.

Exportador dinámico 2.0

Hace algunos años apareció un magnífico plugin para nuestras aplicaciones Velneo, se trataba del exportador dinámico, un plugin realizado por TheSeedSC.

El “Exportador dinámico” permitía crear plantillas personalizadas para exportar los registros de una lista (una vista de datos normalmente) seleccionando entre los campos de la tabla y sus maestros.

Exportador dinámico

Además, disponía de otras funcionalidades muy interesantes:

  • guardar y recuperar plantillas
  • ocultar campos (lista negra)
  • distintos formatos (CSV, HTML, JSON)
  • poder exportar desde cualquier vista de datos con un manejador de evento y dos líneas de JS

Sin embargo, presentaba algunos inconvenientes:

  • La estructura completa de la BBDD se guardaba en tablas en disco y se traspasaba parte de ella a tablas en memoria cuando se quería crear una plantilla, esto hacía que si se cambiaba la estructura de la BBDD (añadir, modificar o eliminar campos y/o tablas) había que borrar las tablas y generar la estructura de nuevo.
  • Las listas negras también estaban guardadas en tablas, enlazadas con la estructura, lo que suponía que se perdían si había que regenerar la estructura.
  • El traspaso de información de las tablas de disco a tablas en memoria se ralentizaba en caso de tablas con muchos campos y enlaces maestros.

Por todo ello un día empezamos a pensar en cómo intentar solucionar algunos de los problemas que presentaba aprovechando novedades del API JS y el nuevo control TreeView, entonces decidimos no guardar la estructura de la BBDD, sino leerla cuando fuera necesario del proyecto Velneo (con VProjectInfo y VTableInfo), además optimizamos su carga, sólo se leen las tablas enlazadas cuando el usuario las abre.

Al no guardar la estructura en tablas no podíamos crear vistas de datos “rejillas” o “árboles” con objetos Velneo, así que usamos el control TreeView para representar tanto los campos disponibles como.

exportador dinámico

El exportador dinámico + “Life is soft”

Finalmente optamos por un enfoque algo más Life Is Soft a la hora de integrar el exportador con nuestras aplicaciones, en lugar de llamarlo con JS desde vistas de datos, preparamos tres procesos  para que pudieran ejecutarse desde cualquier origen lista (“Preparar plantilla”, “Generar datos” y “Preparar plantilla+Generar datos”), además, al estar divididos es posible utilizarlos de forma más flexible, si sólo necesitas que el usuario prepare una plantilla se ejecuta el primero (para guardarla como configuración), si ya tienes la plantilla guardada puedes recuperarla y ejecutar directamente el proceso de “Generar datos”.

También nos permite personalizar la ejecución del exportador:

  • Preparar plantilla
  • Realizar un proceso largo/costoso de búsqueda o generación de registros
  • Pasar el resultado al proceso de generar datos

Para que podáis probarlo vosotros mismos os adjuntamos un pequeño .vin con el código un par de tablas de ejemplos.

Algunas de las mejoras y funcionalidades interesantes para añadir pueden ser:

  • Listas negras de campos
  • Guardar y recuperar plantillas
  • Añadir opciones de formateo a los campos (formatos de tiempo/fecha/hora, eliminar saltos de línea en campos alfabéticos…)
  • Implementar otros formatos de salida (HTML, XML, JSON…)

Si queréis integrarlo con vuestras aplicaciones sólo tenéis que copiar los objetos (y ficheros de script) y modificar el fichero “exp_cfg.js” con el alias de vuestro proyecto.

¿A qué esperas para descargarte el exportador dinámico del Profesor vBacterio?

Pruébalo y déjame un comentario mas abajo

La entrada Exportador dinámico 2.0 aparece primero en AyudaVelneo.

El rayo ordenador de listas

Que levante la mano el desarrollador que no haya escuchado la frase:

“A Velneo le cuesta ordenar listas.

Este ha sido un tema muy popular en el foro oficial de Velneo donde se han propuesto diferentes maneras de ordenar listas de registros utilizando tanto la instrucción nativa “Ordenar lista“, como las de la clase de “VRegisterList”.

 

Si ordenamos una lista por un campo y posteriormente queremos ordenar por otro campo, perdemos la primera ordenación… hasta ahora.

ordenar listas

Ordenar listas con vJavaScript

Hoy proponemos un script/proceso que permite ordenar una lista de registros utilizando distintos tipos de criterios:

Lista de campos

Una lista de campos especificados como cadena, imaginemos que tenemos una tabla de facturas enlazada con una tabla de clientes y queremos obtener los registros de la tabla de facturas ordenados por el nombre del cliente [A → Z, ascendiente] y por fecha de factura [antiguas → recientes, descendiente]

CLIENTE.NAME,A;FECHA,D

Función comparadora

Vamos a crear una función JS que recibe dos objetos VRegister como parámetros y devuelve -1, 0 ó +1 dependiendo de qué registro consideremos mayor o menor, aquí tenemos mayor libertad para definir un criterio de ordenamiento:

function(reg1, reg2){
 //Ordenamos de mayor a menor por longitud del nombre de cliente
 if(reg1.fieldToString(‘CLIENTE.NAME’).length > reg2.fieldToString(‘CLIENTE.NAME’).length)
  return +1;
 if(reg1.fieldToString(‘CLIENTE.NAME’).length < reg2.fieldToString(‘CLIENTE.NAME’).length)
  return -1;
 //Ordenamos de menor a mayor el valor absoluto del campo TEMP
 if(Math.abs(reg1.fieldToDouble(‘TEMP’)) > Math.abs(reg2.fieldToDouble(‘TEMP’)))
  return -1;
 if(Math.abs(reg1.fieldToDouble(‘TEMP’)) < Math.abs(reg2.fieldToDouble(‘TEMP’)))
  return +1;
 return 0;
}

Este método tiene una serie de limitaciones, que si os parece interesante podéis probar a resolver:

  • La ordenación por lista de campos los trata siempre como alfabéticos.
  • El proceso está basado en el algoritmo de ordenación por inserción, que tiene un orden de complejidad O(n2) por lo que el tiempo de ejecución aumenta notablemente con el tamaño de la lista a ordenar, podría sustituirse por un algoritmo quicksort.

Si queréis aportar mejoras o ideas estaré encantado de ir actualizando este experimento

 

¿Ordenas ya tus registros a la velocidad del rayo?

Pruébalo y déjame un comentario mas abajo

Foto: Abel Escobar

La entrada El rayo ordenador de listas aparece primero en AyudaVelneo.

¿Sabes cómo ampliar la información de tus tablas sin tocar su estructura? La solución se llama maestro de extensión.

Comienzas a utilizar Velneo para tus desarrollos y decides utilizar como base de tus aplicaciones, por ejemplo, la open app vErp. Quieres aumentar sus prestaciones sin tocar la base… y comienzan los sudores fríos ¿ahora qué? ¿cómo lo hago? Tranquilo… La solución está en el maestro de extensión.

Maestro de extensión

Al final lo que nosotros queremos es crear nuevos módulos para resolver nuestras necesidades a partir de apps de otras empresas o desarrolladores, sin tocar su estructura, para beneficiarnos de futuras actualizaciones.

La idea es heredar esa app en nuestra solución y utilizar los mecanismos que nos proporciona Velneo para ampliar las funcionalidades que “vienen de serie” en dichas apps.

A nivel de proyectos de aplicación lo tenemos solucionado gracias a la herencia inversa mediante los puntos de inserción y las inserciones de ficha.

A nivel de proyectos de datos tenemos la solución gracias al maestro de extensión.

Pero ¿qué es un maestro de extensión?

El maestro de extensión no es mas que otro tipo de tabla de las que disponemos en Velneo, con unas ciertas particularidades:

  • Es una tabla maestra que necesita de una tabla padre ampliando su información.
  • Sólo se puede crear una tabla maestro de extensión de tablas de tipo maestro normal con clave numérica o maestro normal con clave arbolada. En esta versión (Velneo 20.1) no es posible crear tablas de extensión de tablas submaestras ni históricas ni de otros maestros de extensión.
  • El campo ID del maestro de extensión es un campo de tipo enlace a maestra. Una tabla padre podremos verla como la suma de sus campos y de los que contienen la o las tablas de extensión asociadas.
  • Cuando creamos una tabla de extensión de una tabla padre, Velneo creará en la tabla padre un campo puntero automático hacia el registro del maestro de extensión que compartirá el mismo código (Valor del campo ID). A través de estos podemos obtener los datos de las tablas de extensión de la misma forma que lo hacemos con los punteros a maestro.
  • Al crear la tabla a través del asistente, se generarán los índices complejos NAME, WORDS Y PARTS para poder buscar registros de esta tabla de extensión por los índices correspondientes de la tabla de datos padre.
  • Las tablas de extensión se comportan a nivel de base de datos como una extensión de la tabla padre, por ese motivo Velneo automáticamente añade al maestro de extensión los enlaces plurales de la tabla a la que extiende. Esto permite que podamos navegar directamente a registros históricos de la tabla padre desde la tabla de extensión sin necesidad de realizar una navegación intermedia. En la versión actual (Velneo 20.1) la navegación directa desde el maestro de extensión a los plurales de la tabla padre solamente es funcional cuando la tabla padre y el maestro de extensión están en el mismo proyecto. Si están en proyectos diferentes, para hacer la navegación tendremos que leer el maestro y desde allí cargar los plurales. (Nota extraída de la ayuda de Velneo)

Utilidades del maestro de extensión.

Hay tres situaciones en las que nos puede venir de perlas hacer uso de una tabla de tipo maestro de extensión:

  • Añadir campos a una tabla de una Open App: es el ejemplo típico y mas conocido para el uso de este tipo de tablas. He heredado una open app y no quiero tocar su estructura para beneficiarme de futuras actualizaciones. Es el ejemplo que veremos mas abajo, ampliar la información de la tabla “Contactos” de vErp con datos para un CRM.
  • Reducir el tamaño del registro de una tabla: en algunas ocasiones puede que nos resulte útil crear un maestro de extensión de alguna de nuestras tablas (situada en el mismo proyecto de datos o no). Si la longitud del registro es elevada (recuerda que es una propiedad de la tabla) o si la tabla en cuestión tiene muchos campos que no se usan habitualmente una buena práctica es crear un maestro de extensión.
  • Tablas polimórficas: no es un tipo de tabla como tal. Imaginad que tenemos en una tabla de contactos diferentes tipos: clientes, proveedores, vendedores, transportistas, etc. En lugar de añadir en la tabla de contactos campos específicos para cada uno de los tipos (que no se usarán a no ser que se marque que es de un determinado tipo), podemos crear tablas de extensión para cada uno de los tipos con sus campos específicos.

Ya sabes… no sólo sirven para ampliar la información de una open app.

Creando una tabla maestro de extensión.

Vamos a ver un ejemplo de cómo crear un maestro de extensión en una solución vCrm que hereda de vErp.

Para el ejemplo vamos a crear una tabla que extienda la información de la tabla “Contactos” de vErp añadiéndole campos específicos para el módulo CRM.

  • Pulsamos sobre el asistente de creación de tablas, le asignamos el nombre singular y plural y le indicamos que es de tipo “Maestro de extensión.

Asistente de maestro de extensión I

  • En en siguiente formulario del asistente le indicamos la tabla a la que extiende y además tenemos la posibilidad de marcar si queremos que nos cree los índices complejos NAME, WORDS Y PARTS.

Asistente maestro de extensión II

  • Los dos siguientes formularios del asistente son los típicos para la creación de una tabla maestra: si queremos añadirle los campos estándar y si queremos enlazar con alguna tabla maestra.
  • Sólo faltaría añadir en la tabla los campos que necesitamos para ampliar la información de la tabla de “Contactos” de vErp. En mi caso, he añadido los siguientes campos:

Maestro de extensión vCrm

En esta imagen podéis ver los enlaces plurales que ha creado Velneo automáticamente a la hora de dar de alta el maestro de extensión.

Ya sólo nos faltaría ponerlo en práctica y crear los objetos visuales para mostrar los datos del maestro de extensión…. pero eso lo dejamos para un próximo artículo

¿Has creado ya maestros de extensión en tus aplicaciones?

¿No?

Y a qué esperas para hacerlo, ¿te siguen quedando dudas?

Déjame un comentario mas abajo e intentaré resolverlas.

La entrada ¿Sabes cómo ampliar la información de tus tablas sin tocar su estructura? La solución se llama maestro de extensión. aparece primero en AyudaVelneo.

Cómo mostrar la suma acumulada de los registros seleccionados en el pie de la rejilla

Los que venimos de 6x echamos de menos una instrucción muy útil que había en los pies de las rejillas: “Suma acumulada de los marcados”. Con esta instrucción conseguías que apareciese la suma acumulada de los registros seleccionados por el usuario en en el pie...

La entrada Cómo mostrar la suma acumulada de los registros seleccionados en el pie de la rejilla aparece primero en AyudaVelneo.