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 ( [email protected]_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, [email protected]_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 ( [email protected]_Rotulo_LED_dat, NAME, "DECENA_HORA_" + mid(CHORA, 0, 1), , ,)
        Añadir lista a la salida
Rem ( UNIDADES DE HORA )
Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "UNIDAD_HORA_" + mid(CHORA, 1, 1), , ,)
        Añadir lista a la salida
If ( [email protected]_Rotulo_LED_dat.dat | ((second(currentTime()) % 2) = 0) )
        Rem ( SEPARADOR DE MINUTOS )
        Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "SEP_MINUTOS", , , )
                Añadir lista a la salida
Rem ( DECENAS DE MINUTOS )
Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "DECENA_MINUTO_" + mid(CHORA, 2, 1), , , )
        Añadir lista a la salida
Rem ( UNIDADES DE MINUTOS )
Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "UNIDAD_MINUTO_" + mid(CHORA, 3, 1), , , )
        Añadir lista a la salida
If ( [email protected]_Rotulo_LED_dat.dat )
        Rem ( SEPARADOR DE SEGUNDOS )
        Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "SEP_SEGUNDOS", , , )
                Añadir lista a la salida
        Rem ( DECENAS DE SEGUNDOS )
        Cargar lista ( [email protected]_Rotulo_LED_dat, NAME, "DECENA_SEGUNDO_" + mid(CHORA, 4, 1), , , )
                Añadir lista a la salida
        Rem ( UNIDADES DE SEGUNDOS )
        Cargar lista ( [email protected]_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:[email protected]: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:[email protected]: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.

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.

Comienza el curso escolar 2017/2018

La verdad es que estoy como los niños cuando empiezan el nuevo curso escolar: con mucha ilusión por reencontrarme con los “amigos virtuales” ( o sea tu) y deseando hacer cosas nuevas en el blog.

curso escolarEste 2017 no está siendo como yo esperaba a nivel personal.

Cuando estaba a punto de irme de vacaciones para olvidar mis problemas de salud, (y cuando digo a punto de salir, quiero decir la noche antes con las maletas ya preparadas) tuvimos que llevar a mi hijo mayor al hospital: operación de apendicitis y cancelación de las vacaciones.

Tampoco me puedo quejar. Todo se ha cogido a tiempo y no deja de ser ya una “anécdota” familiar.

Siendo sinceros… alguna asignatura pendiente me ha quedado.

De mis propósitos de año nuevo, algunas asignaturas me han quedado pendientes para “septiembre”:

  • Todavía no he logrado crear un sistema de ingresos recurrentes.
  • Creación de un nuevo curso de iniciación.
  • Escribir artículos con mas regularidad. Esto está muy relacionado con el punto 1… si no logro ingresos recurrentes, tengo que intercambiar tiempo por ingresos… y ahí salgo perdiendo.

Prometo aplicarme para “aprobar” estas asignaturas.

¿Y este nuevo curso escolar qué?

La verdad es que estoy muy ilusionado con el proyecto ayudavelneo.

Sentir que con los artículos ayudo a los desarrolladores que se están iniciando en Velneo a ser mas productivos y a obtener beneficios desde el minuto uno, me produce una gran satisfacción.

Además gracias al blog cada vez mas a menudo me llegan propuestas de trabajo: desarrollos, cursos online, cursos presenciales así como ofertas de trabajo en empresas.

Esta última opción, de momento está descartada.

Como te he comentado anteriormente, he prometido aplicarme para “recuperar” las asignaturas que llevo suspensas.

En esta última parte del año, he decidido emprender las siguientes acciones:

  • Publicar un post todos los martes. Si además hay post de algún invitado, se publicarán los jueves.
  • Crear un nuevo curso de iniciación en Velneo para todos aquellos de vosotros que estáis empezando a desarrollar con la plataforma.
  • Enviar un boletín o newsletter los viernes a todos los suscriptores del blog,  con las novedades y artículos interesantes que aparezcan relacionados con Velneo. Si no te has suscrito todavía, puedes hacerlo al pie de este post.
  • Como los grandes clubes de futbol (quitando al Barcelona este año… jejeje), yo también he “fichado” a un nuevo colaborador para el blog: El “profesor vBacterio“. Algún experimento interesante mezclando Velneo y vJavaScript ya he visto que saldrá de su laboratorio.

Además durante el verano he recibido algunos e-mails en los que me preguntábais si los “Cursos Online” relacionados con QML iban a volver a estar disponibles.

Aunque en un principio había decidido no volver a ponerlos a la venta, al final he recapacitado y vuelven a estar disponibles:

También están disponibles en el menú superior de la web (opción “Cursos”)

De momento esto es todo lo que tenía que contarte..

¿Qué te han parecido mis “medidas” para aprobar en septiembre? ¿Acertadas?

¿Prefieres recibir la newsletter el fin de semana?

Déjame un comentario mas abajo y comenzamos el debate.

La entrada Comienza el curso escolar 2017/2018 aparece primero en AyudaVelneo.

Las variables en Velneo

El tema de las variables en Velneo siempre ha suscitado dudas y algún que otro quebradero de cabeza, debido al mal uso de los planos de ejecución y del ámbito de las variables.

Recordemos el artículo ayudavelneo.com/el-peligro-de-las-variables-en-velneo-v7 para comprenderlo mejor.

En Velneo a Fondo hemos recopilado la información que hay dispersa en diferentes artículos y en la propia ayuda de Velneo y queremos preparar un artículo en el que podamos encontrar lo más interesante sobre el uso de las variables en nuestras aplicaciones.

Si crees que debemos añadir un concepto o idea nueva sobre las variables en Velneo no dudes en comentarlo.

Las variables en Velneo V7

Tipos de variables en Velneo

Las variables en Velneo V7 son objetos que permiten almacenar datos individuales. Hay dos tipos: las variables globales y las variables locales.

La variable global es un objeto del proyecto de datos, cuyo contenido es global a la aplicación y común, en el ámbito de red, para todos los usuarios si su persistencia es en disco, y de carácter local si su persistencia es en memoria.

Un objeto es un elemento definible dentro de un proyecto que, en tiempo de ejecución, realiza las tareas de un programa. La Rejilla es un objeto.

La variable local es un subobjeto definible dentro de un objeto. Se trata de una variable local al objeto en el que ha sido declarada, y solamente será accesible desde ese objeto o desde otros subobjetos del mismo. La persistencia de este tipo de variables es en memoria.

Un subobjeto es un objeto que está contenido en otro objeto y que no tiene ninguna entidad por sí mismo, ya que depende totalmente del objeto contenedor. El manejador de evento es un subobjeto.

Las variables contienen valores de tipo alfabético, numérico, fecha, hora, tiempo y booleano. Además pueden ser al mismo tiempo arrays unidimensionales.

Ámbito de las variables globales en disco

El contenido de una variable global en disco es común a todos los usuarios y planos de ejecución (tanto en los clientes como en el servidor).

Los planos de ejecución entran en juego cuando desarrollamos en una arquitectura cliente-servidor como la de Velneo V7.

Existen 4 planos de ejecución:
       El 1º plano es el hilo principal de ejecución en el cliente, con el que interactúa el usuario de nuestras aplicaciones.
       El 2º plano también se ejecuta en el cliente, pero a diferencia del 1º plano, la ejecución es asíncrona, es decir, no interrumpe el resto de procesos.
       El 3º y 4º planos se ejecutan en el servidor, el primero de forma síncrona y el segundo asíncrona.

Por tanto, si desde una sesión de Velneo vClient V7 se modifica una variable global en disco, esta modificación afectará tanto a los clientes que estén ejecutando la misma instancia como a los procesos que hagan uso de ella en el servidor (procesos ejecutados en 3º y 4º  plano).

Una instancia es una aplicación abierta en Velneo vServer que está en ejecución. Es posible abrir en un mismo Velneo vServer diferentes instancias de una misma aplicación. Una aplicación Velneo está compuesta por proyectos, tanto de datos como de aplicación, que serán instanciados de forma independiente.

Debemos tener en cuenta que cada vez que se usa una variable global en disco, vClient solicitará al servidor el valor de dicha variable, por si ha cambiado, lo que supone una conexión (socket) a través del enganche correspondiente, lo que puede ralentizar el proceso sobre todo en cloud.

Un socket es una conexión que se establece cada vez que queremos comunicar dos máquinas. La comunicación se ralentiza sobre todo al establecer el socket, ya que una vez establecida el traspaso de información es rápido. En cloud nuestras aplicaciones deben generar el menor número de sockets posible y para ello hemos de optimizar nuestras aplicaciones.

Debemos evitar el uso de variables globales en disco en la definición de propiedades de campos de las tablas. Por ejemplo, un valor inicial basado en una variable global en disco ralentizará el alta del registro. En la Interfaz de nuestras aplicaciones, un campo fórmula con una variable global en disco se recalcula en cada registro de la Rejilla o en comandos de Recorrer lista, lo que en redes lentas se traduce en una mala experiencia de usuario.

Ámbito de las variables globales en memoria

Las variables globales en memoria existen solo en la sesión de la máquina donde se ejecuta la aplicación. Si ejecutamos varios vClients en una misma máquina, las sesiones se ejecutan en diferentes espacios de memoria y por lo tanto no comparten las variables globales en memoria.

En el servidor, la instancia de la aplicación comparte la memoria con todas las sesiones iniciadas por los usuarios, en consecuencia en 3º y 4º plano, cualquier cambio de una variable global en memoria en una sesión afectará al resto de sesiones.

Cada vez que un usuario se conecta al servidor mediante vClient se crea una nueva sesión de usuario también llamado enganche. La sesión es efímera, solo debe dejar un rastro en forma de Log o histórico.

Las variables globales en memoria de un mismo proyecto de datos no se replican entre el cliente y el servidor. Si el vClient  modifica una variable global en memoria, ésta misma variable en 3º y 4º plano no se verá afectada por la modificación de vClient, son espacios de memoria separados.

Los procesos en 1º y 2º plano comparten la memoria en la misma sesión de vClient. Un proceso en 2º plano que modifica una variable global en memoria afectará al resto de procesos en 1º y 2º plano.

Una sesión de vClient solo comparte con otros vClient de la red (local o remota) los siguientes datos:

    • Las tablas de la instancia de datos del vServer
    • Las tablas en memoria en 3º y 4º plano de la instancia de datos del vServer
    • Las variables globales en disco
    • Las variables globales en memoria en 3º y 4º plano de la instancia de datos del vServer

Cuando una variable global (en memoria o disco) es modificada en 1º plano, todos los elementos del interfaz activos en ese momento se actualizan inmediatamente. Todas las fórmulas de las propiedades de los objetos se vuelven a calcular. Habrá que tenerlo en cuenta en nuestras aplicaciones para evitar comportamientos no controlados.

Variables del sistema

Aunque la ayuda dice que son variables de tipo local predefinida en el sistema, se puede considerar que su ámbito es global a la aplicación. Están siempre disponibles a través del editor de fórmulas y algunas, como sysUserName, sysCacheClientPath y sysIsAdministrator, se fijan al inicio de la aplicación y su valor estará siempre disponible en cualquier plano de ejecución.

Ámbito de las variables locales

Las variables locales sólo son accesibles desde la instancia del objeto en que se han definido.

Si el objeto es un formulario, las variables locales también son accesibles desde los subobjetos de dicho formulario. Cuando instanciamos el mismo formulario 2 veces, las variables locales de ambas instancias son totalmente independientes.

Los subobjetos de un formulario son los controles, conexiones de evento, manejadores de evento, variables locales, inserciones y extensiones de ficha.

Para insertar un control del proyecto en un formulario usamos un control Vista de datos (o un separador, caja o pila de formularios) que hace de contenedor de dicho control. Las variables locales del control insertado no se comparten con el formulario anfitrión porque el subobjeto es el control Vista de datos y no el objeto incrustado.

Por ejemplo, cuando insertamos una Rejilla en una Vista de datos, las variables locales de la Rejilla no se comparten con las variables locales del formulario.

La tabla no es un subobjeto del formulario y por lo tanto la tabla y el formulario no comparten las variables locales.

Hay una excepción con la compartición de variable locales en el objeto Búsqueda. Si tiene un formulario declarado para introducir las variables locales y éstas coinciden en nombre con las variables locales de la Búsqueda entonces se traspasan automáticamente los valores del formulario a la Búsqueda.

Variables locales especiales

Existen 3 variables locales cuyo identificador está reservado. Se pueden crear manualmente o a través de la opción “Crear variables locales eventos” del menú de Objetos.

    • EVENT_SENDER_ID: De tipo alfabética. Contiene el identificador del control que envía la señal. Estará vacía si el que envía la señal es el propio objeto.
      La variable EVENT_SENDER_ID podemos usarla dentro de un manejador para conocer qué Botón ha sido pulsado si existen varios botones que disparan el mismo manejador de evento.
    • EVENT_SENDER_COL: De tipo alfabética. Permite obtener información de la columna en la que estamos posicionados cuando se lanza la señal. Estará vacía en todos los eventos salvo los de columna editable de rejilla.
    • EVENT_PARAMS: De tipo array alfabética. Contiene información que podrá ser leída desde el manejador de evento que ha ejecutado la señal disparada.

Acceso a variables locales de Vistas de datos

Ya hemos dicho que un objeto del proyecto insertado en un formulario no comparte las variables locales, sin embargo Velneo proporciona comandos que nos van a permitir leer y escribir valores desde el formulario en las Vistas de datos que contenga.

Las Vistas de datos son objetos del proyecto que gestionan Listas de registros de una tabla, la excepción es el formulario que gestiona solo una Ficha. Las Vistas de datos se pueden incrustar en un formulario para mostrar, entre otras cosas, las relaciones maestro-detalle de nuestro proyecto de datos.

Existen 5 controles del formulario que permiten incrustar objetos Vista de datos:

    • Vista de datos propiamente dicha que mostrará objetos aparcables (rejilla, multivista, casillero, …) mediante un proceso cargador
    • Separador de formularios que mostrará varios formularios en pestañas
    • Splitter que mostrará varios formularios con un separador ajustable
    • Pila de formularios para crear asistentes mediante formularios sucesivos
    • Caja de formularios que mostrará varios formularios en otro tipo de pestañas

Existen 2 comandos de Velneo que nos dan acceso a las variables locales del objeto incrustado en la Vista de datos:

    • Interfaz: Set variable local de vista de datos
    • Interfaz: Get variable local de vista de datos

Tened en cuenta que estos 2 comandos solo funcionan con objetos incrustados en formularios como Vista de datos. No se puede acceder a variables locales de otro formulario. Por ejemplo, si queremos acceder a las variables locales de un Dock del marco de la Aplicación tendremos que diseñar 2 formularios, uno principal que será el Dock y otro secundario, incrustado como Vista de datos, que contendrá las variables locales que queremos gestionar. El comando que lee el valor de una variable local quedará de la siguiente manera:

Interfaz: Get variable local de vista de datos (.AUTOEXEC.DOCK_CONFIG.CTR_VISTADATOS, VAR_LOCAL, VAR_LOCAL_RETORNO)

Acceso a las variables en Velneo usando el API

En Velneo se ha desarrollado un API que incluye un conjunto de clases que aportan los objetos y funciones para acceder a los elementos de nuestros proyectos. Para programar el API se han incorporado 2 lenguajes, Javascript y QML. En ambos lenguajes podemos usar el conjunto de funciones del estándar EcmaScript-262 (ver http://doc.qt.io/qt-5/qtqml-javascript-functionlist.html).

La interfaz de programación de aplicaciones, abreviada como API (del inglés: Application Programming Interface), es el conjunto de subrutinas, funciones y procedimientos (o métodos, en la programación orientada a objetos) que ofrece cierta biblioteca para ser utilizado por otro software como una capa de abstracción.

Con el API de Velneo podemos acceder a cualquier variable de nuestros proyectos. La herencia permite el acceso y uso de cualquier objeto de la aplicación desde cualquier script.

La herencia es la propiedad que permite que un proyecto pueda hacer uso de los objetos de otro proyecto.

Acceso con el API a las variables globales

Las variables globales son objetos del proyecto de datos. Desde el API usaremos la clase VApp para el acceso a dichas variables.

La clase VApp representa a la aplicación. Siempre estará instanciada en el objeto global theApp.

Las funciones del objeto theApp para el acceso a variables globales son globalVarTo<tipo>() y setGlobalVar(), la primera obtiene el valor de la variable global (tendremos que especificar el tipo de dato que vamos a obtener) y la segunda establece el valor de la variable global.

La variable global se identifica desde el script con el formato “ALIAS_PROYECTO_DATOS/Identificador

El Identificador es la etiqueta alfanumérica que identifica de forma unívoca al objeto dentro del proyecto y para el mismo tipo de objeto. Este identificador será el que usemos para referenciarlo en las propiedades de otros objetos. El identificador constará de mayúsculas y números exclusivamente.

El objeto theApp representa al proyecto de aplicación principal, es decir, la instancia desde la que iniciamos nuestra aplicación. Por lo tanto, mediante el mecanismo de la herencia tendremos acceso a todos los proyectos de datos de la cadena de herencia. Usar la función mainProjectInfo() de la clase VApp para obtener información del proyecto principal y de todos los objetos de la herencia.

En el siguiente ejemplo obtenemos un JSON con todas las variables globales de la Herencia.


// Obtiene un Array con todas las variables globales en la herencia
// Proyecto principal
var mainProjectInfo = theApp.mainProjectInfo()
// Obtenemos el JSON
alert(JSON.stringify(getAllVarGlobal(mainProjectInfo), null, "  ")

function getAllVarGlobal(ProjectInfo, aLisVarGlobal){
        // Inicializa el array
        aLisVarGlobal = aLisVarGlobal || []
        // Añade al array las variables globales del proyecto
        aLisVarGlobal = getVarGlobal(ProjectInfo, aLisVarGlobal)
        // Proyectos heredados (bucle recursivo en toda la herencia)
        for(var i=0, count=ProjectInfo.legacyProjectCount(); i<count; i++){
                var oProyHeredado = ProjectInfo.legacyProjectInfo(i)
                if (oProyHeredado.type() == 0) {
                        // Solo exploramos los proyectos de Datos
                        getAllVarGlobal(oProyHeredado, aLisVarGlobal)
                }
        }
        return aLisVarGlobal
}

// Devuelve todas las variables globales del proyecto
function getVarGlobal(oProyecto, aVarGlobal){
        var count = oProyecto.objectCount(VObjectInfo.TypeVariable)
        var oObjVarGlobal = null
        for(var i=0; i<count; i++){
                oObjVarGlobal = oProyecto.objectInfo( VObjectInfo.TypeVariable, i )
                aVarGlobal.push ( 
                        {
                                idRef: oObjVarGlobal.idRef(),
                                id: oObjVarGlobal.id(),
                                name: oObjVarGlobal.name(),
                                valor: theApp.globalVarToString(oObjVarGlobal.idRef()).substr(0, 100)
                        }
                )
        }
        return aVarGlobal
}

Acceso con el API a las variables LOCALES

Las variables locales pertenecen a objetos que pueden ser ejecutados desde los proyectos de datos y aplicación. Desde el API usaremos la clase VRoot para acceder al objeto principal que está en ejecución.

La clase VRoot representa al objeto en ejecución. Siempre estará instanciada en el objeto theRoot, accesible desde los scripts del objeto actual.

Las funciones del objeto theRoot para el acceso a las variables locales son VarTo<tipo>() y setVar(), la primera obtiene el valor de la variable local (tendremos que especificar el tipo de dato que vamos a obtener) y la segunda establece el valor de la variable local.

La variable local se identifica con su Identificador único en el objeto al que pertenece.

Para acceder a las variables locales del objeto incrustado en un formulario como una Vista de datos tendremos que obtener el objeto theRoot que representa a dicho objeto incrustado. Existe para ello la función root() que aplicada al objeto Vista de datos nos permitirá acceder a sus variables locales.

Veamos un ejemplo. Obtenemos el ID del registro seleccionado en una Rejilla y lo asignamos a la variable local del formulario incrustado como Vista de datos.

// Formulario principal
var oForm = theRoot.dataView()
// Rejilla con la lista de Fichas
var oGRDLista = oForm.control("GRD_LISTA")
var oLista = new VRegisterList(theRoot)
// Reiniciamos la variable local NID
theRoot.setVar("NID",0)
// Ficha seleccionada en la Rejilla
var nSel = oGRDLista.currentSelect()
if (nSel > -1) {
        // Lista de Fichas de la rejilla
        oGRDLista.getList(oLista)
        // Ficha seleccionada en la Rejilla
        var oFicha = oLista.readAt(nSel)
        // Fijamos la variable local NID
        theRoot.setVar("NID", oFicha.fieldToInt("ID"))
        if (oFicha) {
                // Mostramos la Ficha en el formulario incrustado como Vista de datos
                var oVistaDatos = oForm.control("FRM_INCRUSTADO")
                oVistaDatos.setRegister(oFicha)
                // Establecemos el valor de la variable local de la Vista de datos
                oVistaDatos.root().setVar("NID", oFicha.fieldToInt("ID"))
                // Accedemos al objeto en ejecución de la Vista de datos mediante la función root()
                //         y obtenemos el valor de la variable local de la Vista de datos
                alert(oVistaDatos.root().varToInt("NID"))
        }
}

Existe otra clase VObjectInstance que nos permite instanciar objetos de la aplicación de la misma forma que lo hacemos con el comando de Velneo “Crear manejador de objeto”. Para disparar el objeto usaremos la función exec(). Antes de disparar el objeto podemos asignar valores a las variables locales con setVar(). Después de ejecutar exec() y si éste devuelve true, obtenemos el valor de las variables locales con la función VarTo<tipo>().

Variables globales y locales de tipo Array

Las variables array en Velneo no son un objeto independiente del proyecto. Para disponer de un array tendremos que poner a 1 la propiedad Array de una variable global o local.

Los arrays son siempre unidimensionales y el tipo de dato que contiene lo determina el Tipo de la variable. Los elementos del array se acceden mediante la posición que ocupan, siendo 0 la primera posición. En las fórmulas podemos obtener el valor de un elemento concreto del array usando la sintaxis ID_ARRAY[<posición>].

Acceso a variables array globales

Los valores de las posiciones en un array global se pueden leer desde Velneo con la sintaxis ID_ARRAY_GLOBAL[<posición>], pero la asignación de valores solo se puede realizar a través del API. Se podrá trabajar con variables globales de tipo array a través del API de JavaScript mediante las funciones de variables globales de tipo array de la clase VApp.

El uso de un array global facilita la gestión de determinada información al poder agrupar n-variables globales en una sola.

Las funciones del objeto theApp para el acceso a variables array globales son globalVarArrayTo<tipo>() y setGlobalVarArray(), la primera obtiene el valor de una posición de la variable array global (tendremos que especificar el tipo de dato que vamos a obtener) y la segunda establece el valor de una posición de la variable array global. El segundo parámetro de estas funciones es la posición del elemento del array, empezando en 0. Podemos conocer el tamaño de una variable array global mediante la función globalVarArraySize().

Vamos a ver un ejemplo de gestión de variable array global usando el API de Velneo.
Hemos creado en el proyecto de datos una variable global en memoria G_CONEXION de tipo Array. En ella queremos guardar algunos datos de la Sesión actual.
El tamaño del array se irá adaptando al número de elementos creados.

Disponemos de 2 procesos javascript, uno que inicializa los valores del array y otro obtiene un determinado elemento del array.

// Script PRO_CONEXION_INI_JS – Fija los elementos del array global G_CONEXION
// ----------------------------------------------------------------------------
// Usuario conectado
theApp.setGlobalVarArray("MiApp_dat/G_CONEXION", 0, theApp.userName());

// ¿Es administrador?
theApp.setGlobalVarArray("MiApp_dat/G_CONEXION", 1, theApp.isAdministrator()?"Sí":"No");

// Fecha-Hora de la conexión
var f = new Date();
var dias_semana = new Array('domingo','lunes','martes','miércoles','jueves','viernes','sábado');
var fecha = dias_semana[f.getDay()]
+ " " + f.getDate() + "/" + (((f.getMonth()+1)<10?"0":"")) + (f.getMonth() + 1) + "/" + f.getFullYear()
+ " " + ((f.getHours()<10)?"0":"") + f.getHours() + ":" + ((f.getMinutes()<10)?"0":"") + f.getMinutes();
theApp.setGlobalVarArray("MIApp_dat/G_CONEXION",2,fecha);
//theApp.setGlobalVarArray("MiApp_dat/G_CONEXION", 2, f.toLocaleString());

// Código de Pais
theApp.setGlobalVarArray("MiApp_dat/G_CONEXION", 3, theApp.sysCountryIsoCode());

// Nombre de máquina
theApp.setGlobalVarArray("MiApp_dat/G_CONEXION", 4, theApp.sysMachineName());

// Script PRO_CONEXION_GET_JS – Obtiene un elemento del array global G_CONEXION // -------------------------------------------------------------------------------- // Devuelve el valor del elemento del Array G_CONEXION pasando como parámetro un String CVALOR que describe la información solicitada var aValores = new Array("USER","ISADMIN","DATELOGIN","COUNTRY","MAQUINA") var cValor = theRoot.varToString("CVALOR") var pos = aValores.indexOf(cValor) // Devuelve en VRETORNO el valor del elemento del Array theRoot.setVar("VRETORNO",theApp.globalVarArrayToString("MiApp_dat/G_CONEXION", pos)) En el proyecto de Aplicación podremos usar una función que obtenga directamente cualquier valor del array global: Mensaje(        "Usuario - " + fun:[email protected]_dat.dat("USER") + "\n" +        "Administrador - " + fun:[email protected]_dat.dat("ISADMIN") + "\n" +        "Conectado el - " + fun:[email protected]_dat.dat("DATELOGIN") + "\n" +        "Código de país - " + fun:[email protected]_dat.dat("COUNTRY") + "\n" +        "Máquina - " + fun:[email protected]_dat.dat("MAQUINA"), Informacion)

Acceso a variables array LOCALES

Las variables array locales son el mismo subobjeto variable pero con el valor de la propiedad Array a 1.

Disponemos de un conjunto de comandos Array: que utilizaremos en los procesos para gestionar los valores del array local. Podemos asignar un valor, eliminar uno o todos los elementos del array, obtener el tamaño, ordenar el array e insertar un elemento. Para obtener el valor de un elemento del array no existe un comando, simplemente usamos la sintaxis ID_ARRAY_LOCAL[<posición>].

Existen 2 comandos de Velneo que nos dan acceso a las variables array locales del objeto incrustado en la Vista de datos:

    • Interfaz: Set ítem de variable local array de vista de datos
    • Interfaz: Get ítem de variable local array de vista de datos

Estos comandos funcionan de la misma forma que con las variables locales, indicando el elemento del array empezando en 0.

Desde el API disponemos también de las funciones del objeto theRoot para el acceso a las variables array locales, las cuales son VarTo<tipo>() y setVar(). La primera obtiene el valor de un elemento de la variable array local (tendremos que especificar el tipo de dato que vamos a obtener) y la segunda establece el valor de un elemento de la variable array local. El segundo parámetro de estas funciones es la posición del elemento del array, empezando en 0.

Hagamos un ejercicio interesante sobre el acceso a variables locales array. A veces queremos pasar parámetros a un formulario y nos encontramos que en Velneo solo es posible hacerlo cuando usamos el comando Crear manejador de objeto. Para los formularios que se muestran en modo Vista, o en los comandos Pedir formulario y Modificar ficha con formulario, tenemos que recurrir a variables globales u otras técnicas con el API, json, … En este caso os propongo una solución creada íntegramente con Velneo nativo, que consiste en guardar los parámetros del formulario en una Vista de datos de un dock de la aplicación y usar los comandos de acceso a las variables array locales del objeto incrustado en la Vista de datos.

    • Creamos un formulario FRM_PARAMETROS que solo contenga tantos Arrays como formularios tenga nuestra aplicación que necesiten acceso a parámetros.
    • En el evento PRE_INI de FRM_PARAMETROS opcionalmente podemos inicializar los valores de los parámetros. Los valores del array se almacenan como cadenas de texto. Con los números y booleanos la conversión no presenta problemas, con las fechas y tiempos usaremos el formato ISO.
  Rem (Manejador PRE_INI de FRM_PARAMETROS)
  Rem (Aquí podemos documentar los formularios que van a necesitar acceso a parámetros y los inicializamos si es necesario)
  Rem (Parámetros del formulario FRM_CLIENTE)
  Array: Set ( AFRM_CLIENTE, 1, "parámetro 1", LOK)
  Array: Set ( AFRM_CLIENTE, 2, 200.45, LOK)
  Array: Set ( AFRM_CLIENTE, 3, 1, LOK)
  Array: Set ( AFRM_CLIENTE, 4, dateToString(currentDate(), "yyyy-MM-dd"), LOK)
  Array: Set ( AFRM_CLIENTE, 5, dateTimeToString(currentDateTime(), "yyyy-MM-dd hh:mm"), LOK)
  Rem (Parámetros del formulario FRM_PEDIDO)
  Array: Set ( AFRM_PEDIDO, 1, "", LOK)
  
    • En un dock de la aplicación insertamos un control Vista de datos CTR_PARAMETROS con el formulario FRM_PARAMETROS. La Vista de datos tendrá la propiedad Visible a 0 porque no necesita interfaz, sin embargo será un contenedor de parámetros que funcionalmente actuará igual que las variables globales en memoria, ya que accederemos a él en toda la aplicación a través del objeto Marco Autoexec.
    • Y eso es todo. Ya podemos fijar valores de los parámetros antes de ejecutar un formulario y leer dichos parámetros en el PRE_INI del formulario.

En un proceso determinado ejecutamos lo siguiente:

  Crear nueva ficha en memoria (hNuevaFicha, [email protected])
    Rem ( Establecemos los parámetros que deben tenerse en cuenta en el formulario)
    Interfaz: Set ítem de variable local array de vista de datos (.AUTOEXEC.DOCK_APP.CTR_PARAMETROS, AFRM_CLIENTE, 1, "CODIGO_HU33")
    Interfaz: Set ítem de variable local array de vista de datos (.AUTOEXEC.DOCK_APP.CTR_PARAMETROS, AFRM_CLIENTE, 2, 2565.32)
    Pedir formulario ([email protected], LOK)
    If (LOK)
      Alta de ficha (hNuevaFicha)
        Mensaje ("Nueva ficha: " + #NAME)

En el manejador PRE_INI del formulario FRM_CLIENTE_EDI:

  If (! registerExist())
    Rem ( Obtenemos los valores iniciales desde el formulario de FRM_PARAMETROS)
    Interfaz: Get ítem de variable local array de vista de datos (.AUTOEXEC.DOCK_APP.CTR_PARAMETROS, AFRM_CLIENTE, 1, CNOMBRE_INI)
    Interfaz: Get ítem de variable local array de vista de datos (.AUTOEXEC.DOCK_APP.CTR_PARAMETROS, AFRM_CLIENTE, 2, NIMPORTE_INI)
    Modificar campo (NAME, CNOMBRE_INI)
    Modificar campo (IMPORTE, NIMPORTE_INI)

Conclusión

En este artículo hemos hecho un repaso de los aspectos más importantes del objeto variable de Velneo. Para más detalles de los comandos y funciones del API acudir siempre a la documentación de Velneo en el apartado de vDevelop.

La manera más rápida de acceder es buscar en Google la expresión “variable velneo”.

Tened muy claros los conceptos de ámbito de las variables y cómo acceder a las variables globales y locales tanto desde otros objetos como desde el API.

Si crees que falta algo importante sobre las variables en Velneo no dudes en comentarlo.

La entrada Las variables en Velneo aparece primero en AyudaVelneo.

Formación Velneo V7 para programadores avanzados

Gracias a colaboración empresarial entre TipeSoft y AyudaVelneo, se ha impartido la semana pasada el “Seminario de introducción a QML y vJavaScript“. Hemos logrado, con cierto éxito, poner en marcha esta nueva línea de formación avanzada sobre Velneo V7. Esperamos que en el futuro nos permita ayudaros en vuestra formación tecnológica avanzada para Velneo V7. Durante este primer seminario, nos hemos esforzado en resumir y sintetizar la apertura de la plataforma de desarrollo Velneo V7. La nueva API, la introducción de JavaScript como lenguaje natural y la incorporación de QML como tecnología de desarrollo de interfaces de usuario hacen de Velneo V7 una plataforma muy interesante para escenarios empresariales donde la movilidad es un factor importante. Todas ellas en combinación, nos facilitan herramientas suficientes para afrontar desarrollos tecnológicos en el área de movilidad, mejoras de interfaces de usuario y facilidades de integración entre plataformas. Este primer seminario, es el primero de una serie que impartimos en los próximos meses. El objetivo de esta nueva línea de formación es facilitar conocimiento avanzado en tecnologías relacionadas directa o indirectamente con Velneo V7. Si estás pensando: en desarrollar aplicaciones Velneo V7 para dispositivos móviles en integrar tus [...]

El artículo Formación Velneo V7 para programadores avanzados fue publicado en Ayudavelneo por Francisco José Vila Martín

Mi iniciación en el API de Velneo V7 para JavaScript

Cuando Velneo anunció el API con toda suerte de ventajas y parabienes, lógicamente me interese por el tema, pero enseguida me pregunté ¿pero bueno como empiezo con esto? y lo deje para más adelante. Se sucedieron las versiones y la teórica potenciación de Javascript de Velneo pero seguía sin enterarme de nada, con complejo de tonto, leía y releía la documentación pero solo sacaba como útil Copiar y Pegar “Regenerar área de datos e índices”. Un buen día se publica en el foro un script que me pareció bastante legible y sencillo, lo copie y me puse a activarlo y ¡funciono!. Vaya, vaya, pues parece que por ahí van los tiros. Sobre la base de ese script comencé a añadirle funciones, releer las clases, intentar ver si funcionaban las funciones y métodos y al ir logrando resultados positivos, el ánimo e interés fue en aumento hasta lograr los primeros script útiles. Vin como guía del API de Velneo V7 para JavaScript Fue para mí tan desagradable el comienzo que además de quejarme repetidamente vía soporte, se me ocurrió por necesidad, de tener a mano las rutinas logradas para con esa chuleta facilitarme el desarrollo de nuevos scripts y [...]

El artículo Mi iniciación en el API de Velneo V7 para JavaScript fue publicado en Ayudavelneo por Benito Lavandeira

¿Sabes cómo servir aplicaciones velneo V7 vía web?

Ayer tuvo lugar el primer hangout regalo de Papá Noel a la comunidad de desarrolladores Velneo V7. En este hangout Cristian Camilo Vásquez nos mostró la forma de servir aplicaciones Velneo V7 vía web gracias a Cirrus y nos presentó su plataforma cloud vClouden que posibilita a los desarrolladores de Velneo v7 convertir sus aplicaciones estandar en soluciones SaaS sin necesidad de conocimientos web o cloud. Sigue leyendo si quieres saber lo que dio de si la entrevista Antes de comenzar con el resumen del hangout, quiero dar las gracias [...]

El artículo ¿Sabes cómo servir aplicaciones velneo V7 vía web? fue publicado en Ayudavelneo por Francisco José Vila Martín

Xelcron como referente de facturación electrónica en México con Velneo V7

En esta video-entrevista del “Campus AyudaVelneo” Arturo Miranda, responsable tecnológico de la empresa Xelcron nos cuenta como se han convertido en uno de los referentes de la facturación electrónica en México con la ayuda de Velneo V7. Debido a un cambio en la legislación mexicana (que obligaba a utilizar la facturación electrónica en las operaciones empresariales), vieron una oportunidad de negocio y decidieron apostar por ella, una vez que acababan de cambiar de plataforma de desarrollo. Ésta plataforma se adaptaba perfectamente a los requerimientos que estaban buscando: velocidad de desarrollo y bajo coste. Acababan de encontrar Velneo [...]

El artículo Xelcron como referente de facturación electrónica en México con Velneo V7 fue publicado en Ayudavelneo por

¿Cómo escalar una imagen en Velneo V7?

Tras muchos intentos y cabezazos una vez mas he conseguido mi propósito que era poder escalar una imagen en Velneo V7, en tiempo real para no cargar en la BD una foto de 20MB y quien sabe si nuestros amigos usuarios serian capaces de seleccionar alguna de 80MB. Alguien soez e inteligente diría que existen métodos de control, ¡Bingo eres un crack! pero acabas de pesarle la pelota al usuario de tu aplicación. Muy posiblemente esté ajeno a algo llamado Photoshop o Gimp seré algo mas atrevido, alguno seguro que no sabe ni lo que es PAINT. Nuestros usuarios [...]

El artículo ¿Cómo escalar una imagen en Velneo V7? fue publicado en Ayudavelneo por