La nueva rejilla ya está en un avanzado estado de desarrollo. A continuación os dejo un primer informe de las novedades que aporta.
Características:
- Agrupamientos multiples
- Totales y Subtotales
- Bandas
- Menú de columnas (permite ocultar/ver)
- Fijar columnas a izquierda/derecha (no les afecta el scroll horizontal)
- Multiples tipos de controles de edición
1. Agrupamientos
Agrupar por una columna consiste en formar grupos con las fichas de la lista que tienen el mismo valor en esa columna. La rejilla se convierte entonces en un arbol con los distintos valores de la columna en los nodos primarios que al abrirlos nos despliegan las fichas de su grupo.
Se puede agrupar por una o varias de las columnas pasando a tener el arbol mas niveles.
2. Totales y Subtotales
La rejilla dispone de pié con totales globales de la rejilla y piés de grupos con subtotales. Las operaciones que se pueden realizar en cada columna son: Ninguno Suma, Máximo, Mínimo, Nº items y Porcentaje.
3. Bandas
Permiten agrupar varias columnas con distintas dimensiones.

4. Menú de columnas
Permite ver/ocultar columnas de la rejilla en tiempo de ejecución. Se activa pulsado el botón de la izquierda de la cabecera.
5. Fijar columnas a izquierda/derecha
Estas columnas no se verán afectadas por el scroll horizontal, permaneciendo fijas a izquierda y/o derecha mientras movemos el centro a izquierda/derecha.
6. Multiples tipos de controles de edición
- Auto en función del contenido
- Edit numérico
- Edit de texto una linea
- Edit de texto multilineas
- Edit de texto multilineas en popup
- Edit de maestro
- Edit de maestro a estatica
- Editor de fechas
- Editor de horas
- Editor de fechas/horas
- CheckBox
- ComboBox de maestro
- ComboBox de maestro a estatica
- Imágenes
- Imágenes en popup
- Barra de progreso
- Deslizador
- Reloj
- Manómetro
- Vista de datos
Debido a un herpes que me ha salido en el brazo izquierdo, voy a parar de programar unos dias. No me pilló mal del todo, el vJavaScript está casi acabado.
De todos modos iré publicando las tres clases que faltan pués ya estan implementadas.
No viene mal esta parada, así doy tiempo a los de pruebas para que me alcancen.

El objeto VRoot representa al objeto v7 en ejecución. Dispone de funciones para ver o modificar las variables locales y de sistema del objeto, obtener información del objeto (api), transacciones…
Veamos algunos ejemplos:
- Tenemos un formulario con un Evento-Slot en lenguaje JavaScript: el VRoot del Evento-Slot representa al ejecutor del formulario.
- Ejecutamos un proceso JavaScript con una accion: el VRoot del proceso representa al ejecutor del proceso en v7.
Si el objeto v7 es una vista de datos (rejilla, formulario…) estarán disponibles en VRoot las funciones de manejo de interfaz como obtener un control de un formulario con getWidget(Id), pudiendose usar las funciones del objeto widget que devuelve.
Funciones:
Api del objeto
Variables locales
- String varToString( String szID );
- double varToDouble( String szID );
- Number varToInt( String szID );
- QDateTime varToDateTime( String szID );
- QDate varToDate( String szID );
- QTime varToTime( String szID );
- void setVar( String szID, String szValor );
- void setVar( String szID, double dValor );
- void setVar( String szID, int nValor );
- void setVar( String szID, Boolean bValor );
- void setVar( String szID, QDateTime dt );
- void setVar( String szID, QDate date );
- void setVar( String szID, QTime time );
Variables de sistema
- Number sizeList();
- Number posList();
- Number currentPage();
- Number lastPage();
- String userName();
- String pathCacheClient();
- Boolean isAdministrator();
Transacciones
- Boolean openTrans( String szTitulo );
- Boolean isTransOpen();
- Boolean submit();
- Boolean revert();
Vista de datos
- Object content(); // Devuelve VRegister, VRegisterList o Nulo
- Widget getWidget( String szIDCompuestoControl );
Ejemplos:
1: Iniciar transaccion
if (VRoot.openTrans("Titulo"))
{
var bOK = true;
var szErrMsg = "";
for( var x=0; bOK && x < VRegisterList.sizeList(); x++)
{
var registro = VRegisterList.readLockingAt(x);
bOK = registro.isOK();
if ( bOK )
{
registro.setField( "IDCAMPO1", dato );
registro.setField( "IDCAMPO2", hoy );
.....
registro.modify();
bOK = registro.isOK();
}
if ( !bOK )
szMsg = registro.errorMsg();
}
if ( !bOK )
{
VRoot.revert();
.... // Mensaje de error
}
}
else
{
.... //Mensaje de error
}
Los proyectos ahora tiene una nueva propiedad, Alias, editable en el cuadro de diálogo de propiedades del proyecto. Un referencia a un objeto V7, o idRef, es un string con el alias de un proyecto + el identificador de un objeto v7, separados por “/”. Tambien se puede usar el id del fichero en lugar del alias pero es menos legible.
Por ejemplo para ejecutar desde javascript la accion “VER_CLIENTES” del proyecto alias “MI_ERP” usaremos la siguiente función del objeto VMainWindow:
VMainWindow.runAction( "MI_ERP/VER_CLIENTES" );
En QML en las formulas “Url imagen” el idRef forma parte de una estructura mayor:
"image://velneo/?/ALIAS_PROJECT/IDOBJETO/[DATO]"
El caracter marcado con ? puede ser:
- D – Objeto Dibujo: “image://velneo/D/ALIASPRO/IDOBJETO”
- I – Icono de estática: “image://velneo/I/ALIASPRO/IDTABLAEST/Campo”
- C – Campo objeto dibujo: “image://velneo/C/ALIASPRO/IDTABLA/Campo”
Ejemplo de fórmula url imagen para qml:
Campo objeto dibujo de la ficha en curso o un Objeto-Dibujo si el campo está vacío.
choose(#CARTEL:isEmpty(),
"image://velneo/D/CINE_APP/FILM_128",
"image://velneo/C/CINE_APP/PELICULAS/" + #CARTEL)
o bien con el id del fichero
choose(#CARTEL:isEmpty(),
"image://velneo/D/2btkzgbl.vca/FILM_128",
"image://velneo/C/2btkzgb5.vcd/PELICULAS/" + #CARTEL)

El lenguaje JavaScript no solo lo he implementado en procesos, también en fórmulas. Cualquier propiedad tipo fórmula de cualquier objeto puede ahora ser escrita en V7 o JavaScript, independientemente del lenguaje de las otras fórmulas. Lo mismo sucede con los campos tipo fórmula dinámica que ahora pueden escribirse en V7 o JavaScript.
En el nuevo editor de fórmulas, más simple y eficaz, disponemos de un combobox, situado en la toolbar superior, donde podemos seleccionar el lenguaje deseado: V7 o JavaScript. Los asistentes como “Insertar campo” tienen en cuenta el lenguaje seleccionado e insertan el texto con la sintaxis adecuada.
Por ejemplo al insertar el campo NAME con lenguaje V7 será:
#NAME
y con JavaScript será:
VRegister.fieldToString(“NAME”)
Observese que en JavaScript ya elige el asistente automáticamente la función de VRegister según el tipo de campo, decimales, signo ….

A las fórmulas JavaScript les he conectado un objeto de la clase VRegister a traves del cual se tiene acceso al contenido de los campos, variables locales, globales y de sistema. Solo está disponible el juego de funciones de lectura, no el de modificación como en procesos, pués el objetivo de las fórmulas es obtener un valor.
También les he conectado el objeto VApp, la aplicación, disponible también en procesos y del cual hablaré en otro post.
Los objetos de esta clase representan una lista de fichas de una tabla. Dispone de funciones de manejo de la lista y sus items pudiendose obtener objetos de la clase VRegister por index, en modos lectura y lectura con bloqueo si vamos a modificar.
Las funciones del navegante devuelven otro objeto clase VRegisterList con la lista del maestro o historico.
La funcion sort está sobrecargada pudiendo llevar varios pares de parametros campo y bDescendente.
Funciones:
Api de tabla
Lista & items
- Number sizeList();
- Number posList();
- void clear();
- void invert();
- void sort( String szIdCompuestoCampo, Boolean bDescendente, …. );
- void append( VRegister register );
- void append( VRegisterList registerList );
- void cross( VRegisterList registerList );
- void remove( VRegister register );
- void remove( VRegisterList registerList );
- void removeAt( int nIndex );
- VRegister readAt( int nIndex );
- VRegister readLockingAt( int nIndex );
Navegante
- VRegisterList loadPlurals( String szIDHistorico );
- VRegisterList loadMasters( String szIDPrimarioCampo );
Ejemplos:
1: Navegante / Plurales de todos
var facturas = VRegisterListIn.loadPlurals("FACTURAS");
VRegisterListOut.append(facturas)
2: Recorrer la lista modificando
if (VRoot.openTrans("Titulo"))
{
for( var x=0; x < VRegisterListIn.sizeList(); x++)
{
var registro = VRegisterListIn.readLockingAt(x);
if (registro.isOK())
{
registro.setField( "IDCAMPO1", dato );
registro.setField( "IDCAMPO2", hoy );
.....
registro.modify();
if (!registro.isOK())
... //mensaje de error
}
}
// No hace falta hacer VRoot.submit(), lo hace v7 automaticamente
}
Cada proyecto de Velneo V7 contiene un directorio donde podemos crear una estructura de carpetas y guardar en ellas los ficheros qml, javascript … y sus ficheros auxiliares.
Al ejecutar una aplicación con vClient o vDataClient, se cargan tambien los directorios de scripts de cada proyecto de la aplicacion.

Un mismo fichero qml o javascript se puede usar desde distintos objetos V7. Además hay distintos tipos de objetos v7 que los usan como procesos, listas qml y formularios qml. Un mismo fichero javascript o qml puede ser usado en objetos con distintas entradas y salidas, tabla y/o ficha/lista, controlando el programador mediante las funciones API de los objetos de entrada/salida que nos da vJavaScript. Tambien se puede asumir que un fichero javascript o qml tiene una tabla de entrada y/o salida determinadas, con el nivel de abstraccion deseado en cada fichero script.
Para introducir en un objeto v7 la propiedad “Fichero script” en el edit disponemos de un botón que nos presenta un arbol con los directorios de scripts del proyecto en curso y sus proyectos heredados.
Velneo v7 incorpora tambien editores de codigo fuente para los distintos lenguajes soportados.
Se puede usar “import” en los ficheros fuente qml para importar otros ficheros qml, javascript o carpetas enteras contenidas en los directorios scripts del proyecto y heredados.
Los objetos de esta clase contienen la informacion de la estructura de una tabla.
Tiene funciones generales de la tabla, como ver su id o su tipo, y funciones para obtener informacion de sus subobjetos: campos, indices e historicos.
Tambien nos permite obtener otros VTablaInfo de las tablas enlazadas como maestros o historicos.
Funciones:
Tabla
- String id();
- String idRef();
- String name();
- String singleName();
- Number type();
- Boolean isInMemory();
- Number registerLength();
Campos
- Number fieldCount();
- String fieldId( Number nCampo );
- String fieldName( Number nCampo );
- Number fieldType( Number nCampo );
- Number fieldObjectType( Number nCampo );
- Number fieldBufferLen( Number nCampo );
- Number fieldDecimals( Number nCampo );
- Boolean fieldIsSigned( Number nCampo );
- Number fieldMinimumValue( Number nCampo );
- Number fieldMaximumValue( Number nCampo );
- Numer fieldBindType( Number nCampo );
- String fieldBoundedTableId( Number nCampo );
- VTableInfo fieldBoundedTableInfo( Number nPlural );
- String fieldParentFieldId( Number nCampo );
- Number fieldParentFieldNumber( Number nCampo );
Indices
- Number indexCount();
- String indexId( Number nIndex );
- String indexName( Number nIndex );
- Number indexType( Number nIndex );
Historicos
- Number pluralCount();
- String pluralId( Number nPlural );
- String pluralName( Number nPlural );
- String pluralBoundedTableId( Number nPlural );
- VTableInfo pluralBoundedTableInfo( Number nPlural );
Localizadores por id
- Number findField( String szIDPrimarioCampo );
- Number findIndex( String szIDPrimarioIndice );
- Number findPlural( String szIDPrimarioHist );
Enumeraciones:
Tipos de tablas
- 0 – Maestro
- 1 – Histórico
- 2 – Submaestro
- 3 – Arbolado
Tipos de campo
- 00 – Alfa256
- 01 – Alfa128
- 02 – Alfa64
- 03 – Alfa40
- 04 – AlfaLatin1
- 05 – AlfaUtf16
- 06 – Numerico
- 07 – Fecha
- 08 – Hora
- 09 – Tiempo (fecha y hora)
- 10 – Booleano
- 11 – Objeto
- 12 – FormulaNumerica
- 13 – FormulaAlfa
- 14 – FormulaFecha
- 15 – FormulaTiempo (fecha y hora)
- 16 – // No usado
- 17 – // No usado
- 18 – PunteroVirtual
Tipos de campos objeto
- 0 – Imagen
- 1 – Texto
- 2 – RichText
- 3 – Binario
- 4 – Formula dinamica
Tipos de enlaces de campo (bindType)
- 0 – Ninguno
- 1 – Maestro
- 2 – Estatica
- 3 – IndirectoReal
- 4 – IndirectoVirtual
- 5 – SingularPluralPosicion
- 6 – SingularPluralIndice
- 7 – Hermano
Tipos de indices
- Clave unica
- Palabras
- Multiples claves
- Acepta repetidas
- Trozos de palabras
Ejemplos:
1: Controlar si es una tabla maestra normal
if (0 == VRegisterIn.tableInfo().type())
{
.....
}
o bien
if (0 == VRegisterListIn.tableInfo().type())
{
.....
}
Los objetos de esta clase representan una ficha de una tabla.
Los register pueden ser creados:
- Automaticamente por v7 como VRegisterIn y VRegisterOut al inicio de un script lanzado desde uno o varios objetos V7 con entrada o salida ficha.
- Desde otro objeto en javascript como con la funcion readAt de la clase VRegisterList que devuelve un VRegister.
Dispone de funciones para gestionar los contenidos de los campos por identificador simple o compuesto y por número de campo. Además se pueden ver los contenidos previos de los campos, cuando se leyó la ficha.
Tambien dispone de una funciones para obtener la subclase del tipo VTableInfo que nos da informacion api de la tabla y de sus campos, indices e historicos para ver las propiedades de estos objetos como por ejemplo el tipo de un campo, su identificador o su numero de decimales.
Para edición tenemos funciones de alta, baja y modificación asi como de control de errores.
Y al más puro estilo v7 las funciones de navegante.
Funciones:
Informacion api de tabla
Contenido de campos por identificador
- String fieldToString( String szIDCompuestoCampo );
- double fieldToDouble( String szIDCompuestoCampo );
- int fieldToInt( String szIDCompuestoCampo );
- QDateTime fieldToDateTime( String szIDCompuestoCampo );
- QDate fieldToDate( String szIDCompuestoCampo );
- QTime fieldToTime( String szIDCompuestoCampo );
- Boolean fieldIsEmpty( String szIDCompuestoCampo );
- Boolean fieldHasChanged( String szIDCompuestoCampo );
Contenido de campos por numero de campo
- String fieldToString( Number nCampo );
- double fieldToDouble( Number nCampo );
- Number fieldToInt( Number nCampo );
- QDateTime fieldToDateTime( Number nCampo );
- QDate fieldToDate( Number nCampo );
- QTime fieldToTime( Number nCampo );
- Boolean fieldIsEmpty( Number nCampo );
- Boolean fieldHasChanged( Number nCampo );
Old campos por identificador
- String oldFieldToString( String szIDPrimarioCampo );
- double oldFieldToDouble( String szIDPrimarioCampo );
- Number oldFieldToInt( String szIDPrimarioCampo );
- QDateTime oldFieldToDateTime( String szIDPrimarioCampo );
- QDate oldFieldToDate( String szIDPrimarioCampo );
- QTime oldFieldToTime( String szIDPrimarioCampo );
Old campos por numero de campo
- String oldFieldToString( Number nCampo );
- double oldFieldToDouble( Number nCampo );
- Number oldFieldToInt( Number nCampo );
- QDateTime oldFieldToDateTime( Number nCampo );
- QDate oldFieldToDate( Number nCampo );
- QTime oldFieldToTime( Number nCampo );
Modificación de campos por identificador
- void setField( String szIDPrimarioCampo, String szText );
- void setField( String szIDPrimarioCampo, double dValor);
- void setField( String szIDPrimarioCampo, int nValor );
- void setField( String szIDPrimarioCampo, QDateTime dt );
- void setField( String szIDPrimarioCampo, QDate date );
- void setField( String szIDPrimarioCampo, QTime time );
Modificación de campos por numero de campo
- void setField( Number nCampo, String szText );
- void setField( Number nCampo, double dValor);
- void setField( Number nCampo, int nValor );
- void setField( Number nCampo, QDateTime dt );
- void setField( Number nCampo, QDate date );
- void setField( Number nCampo, QTime time );
Estado
- Boolean exist();
- Boolean isModified();
- Boolean isFieldModified( String szIDPrimarioCampo );
- Boolean isFieldModified( Number nCampo );
Operaciones de disco
- Boolean addRegister();
- Boolean modifyRegister();
- Boolean deleteRegister();
- Boolean isOK();
- Number errorNumber();
- String errorMsg();
Navegante
- VRegisterList loadPlurals( String szIDHistorico );
- VRegister readMaster( String szIDPrimarioCampo );
- VRegister readLockingMaster( String szIDPrimarioCampo );
Variables locales
- String varToString( String szID );
- double varToDouble( String szID );
- Number varToInt( String szID );
- QDateTime varToDateTime( String szID );
- QDate varToDate( String szID );
- QTime varToTime( String szID );
Variables de sistema
- Number sizeList();
- Number posList();
- Number currentPage();
- Number lastPage();
- String userName();
- String pathCacheClient();
- Boolean isAdministrator();
Enumeraciones:
Errores
- 0 – OK
- 1 – Error desconocido
- 2 – Error: No hay transacción en curso
- 3 – Error alta
- 4 – Error baja
- 5 – Error modificación
- 6 – Error lectura
- 7 – Error lectura con bloqueo
- 9 – Error direccion de ficha nula
- 8 – Error index fuera de rango
Ejemplos:
1: Carga un plural
var facturasRegisterList = VRegisterIn.loadPlurals("FACTURAS");