Por Luis Guerra DC_Demo.zip
El presente
artículo está escrito con la intención de dar a los desarrolladores de Visual FoxPro
una introducción e ideas para agregar a las aplicaciones que desarrollan
capacidades de Consultas Dinámicas muy parecidas a las tablas pívot de Excel o
a los cubos que se crean con los Servicios de Análisis de SQL Server 2000 o
similares, también llamados Cubos.
Para lograr
este objetivo he usado el DynamiCube, que es un control ActiveX. El control
DynamiCube es un control que permite obtener y mostrar enormes cantidades de
datos almacenados en bases de datos relacionales en una forma resumida y tabulada
que ayuda al usuario final a realizar decisiones precisas. Los datos numéricos
pueden ser obtenidos de múltiples Fuentes, tabulados, resumidos y presentados
al usuario en un cubo multidimensional. El usuario final puede manipular la
vista, mover dimensiones y cambiar el orden para responder mejor a sus
necesidades de análisis. DynamiCube es n-dimensional y está limitado solamente
por los recursos disponibles del entorno de la PC donde se ejecuta. Cada
dimensión consiste de un número finito de puntos de datos. Estos puntos de
datos son usados para localizar un elemento de datos individual.
Para poder
simplificar algunas explicaciones, en algunos casos me voy a referir al control
DynamiCube simplemente como cubo. En principio se va a crear un formulario y se
le va pegar el control DynamiCube al mismo. El control aparece en la lista de
controles como la clase DCube Class.
Tal como se ve en la figura siguiente:
Una vez
seleccionado el control, hacemos clic en Ok
y se mostrará el control como un rectángulo con fondo blanco al cual le
pondremos ‘oleCube’ en la propiedad Name,
tal como se puede observar en la siguiente figura:
El control
DynamiCube soporta varias tecnologías para acceder a datos. Para ver cuales son
las tecnologías y cual deseamos usar hacemos clic secundario sobre el control y
seleccionamos ‘DCube Class Properties’, como observamos en la siguiente figura:
Después de lo
cual se mostrará una ventana con varias páginas en la primera de las cuales se mostrará
un combobox correspondiente al tipo de conexión (Connection Type) con una lista
de tecnologías que se pueden usar para acceder a datos.
Como se ve, se
pueden usar varias tecnologías entre las que destacan ODBC, ADO (OLE DB) y DAO,
además del modo Unbound que permite
llenar los datos del cubo en tiempo de ejecución. El modo Unbound tiene la
ventaja de que se puede llenar el cubo desde cualquier fuente de datos de que
dispongamos en tiempo de ejecución, pueden ser cursores, vistas, tablas, variables
de memoria, arreglos, etc. La desventaja es que no se puede diseñar el
DynamiCube en tiempo de desarrollo, lo que sí se puede hacer con las otras
tecnologías de acceso a datos tales como el ODBC que permite crear una
instrucción SELECT en tiempo de desarrollo lo que es usado para diseñar el
cubo, esto se hace en la página Layout de la misma ventana de propiedades del
DynamiCube y que facilita enormemente el diseño del mismo. Vamos a dar un
vistazo rápido de cómo se diseñaría el DynamiCube con una conexión ODBC a una
base de datos SQL Server 2000 y cómo se vería:
Primero se
define el tipo de conexión, luego la cadena de conexión así como la instrucción
SELECT-SQL que obtendrá los datos:
Luego está la
página Time Series que permite
definir algunos tipos de datos relacionados a fechas que podrían usarse como
datos del cubo tales como año, trimestre, mes y semana. En este caso no se va a
usar ninguno de esos campos, pero se muestra por cuestiones didácticas:
Luego, se
definen los campos que se van a mostrar y su posición dentro del cubo, para
esto se va a la página Layout y se
pulsa el botón Retrieve Fields para
que en la lista aparezcan todos los campos que el SELECT hace disponible, de
los cuales se van a usar algunos, esto se hace arrastrando el campo desde la
lista hasta la posición deseada:
En la página Fields, se pueden cambiar los títulos o
encabezados que van a tener los campos en tiempo de ejecución:
En la página Preferences, se puede cambiar el aspecto
que va a tener el cubo, para lo cual hay varios comboboxes y checkboxes que
corresponden a diferentes partes del mismo y que sirven para darle un estilo
personalizado ante el usuario final, aunque desde mi punto de vista los valores
predeterminados son buenos.
En la página Printer, se va a especificar el
encabezado, pie de página, márgenes y justificación cuando se imprima o se haga
una vista preliminar de la impresión, así como si se desea que se repitan en
cada página los encabezados:
En la página Color, se pueden especificar los colores
que van a tener diferentes partes del DynamiCube, tales como colores de fondo y
de letras de los encabezados así como de los datos:
Y por último en la
página Fonts, se podrá especificar
los tipos de letras para cada parte del cubo:
Luego hacemos clic en
el botón Ok y ejecutamos el formulario, el cubo se verá más o menos de la
siguiente forma:
El usuario final puede
mover los campos de un sitio a otro, es decir, hacer que los campos estén como
columnas, filas y/o páginas (área superior del DynamiCube, también se le llama
área de filtro, más adelante veremos por qué), los campos de datos (las
cantidades) no se pueden mover. De esa forma el usuario puede construir varios
reportes de acuerdo a cómo haya distribuido los campos, por ejemplo, puede
arrastrar el campo Mes hasta el área
de los campos fila, pero al costado derecho del campo Cuenta, con lo cual el cubo se vería así:
Además si se desea podemos
cambiar el campo al área de campos de columna, con lo cual, el cubo quedaría
así:
Pero eso no es todo, se
pueden filtrar los datos como sea necesario, por ejemplo podemos abrir el campo
Año como un dropdown y se mostrarán
los datos correspondientes, se mostrarán, en este caso, los años 2002 y 2003:
Si deseamos ver
solamente los datos del año 2002, quitamos el check del año 2003 y luego
hacemos clic en cualquier parte del cubo para que se cierre el dropdown y
mostrar sólo los datos del año 2002:
Similarmente, sí sólo
deseamos ver los datos del primer semestre del año 2002, basta con abrir el
dropdown del campo Mes y quitar el
check de los meses correspondientes al segundo semestre:
El cubo se mostrará
así:
Como se ha visto, se
puede diseñar cómo uno desea ver el cubo, en tiempo de desarrollo, todo desde
la ventana de propiedades del DynamiCube. Para cada opción hay una propiedad
disponible que también se puede acceder mediante programación, aunque sería más
complicado hacerlo así. Los resultados son muy buenos, por no decir excelentes.
Ahora volviendo al tema
central de este artículo, nos concentraremos en el uso del DynamiCube en modo
Unbound para poder acceder a los datos desde una consulta de tablas VFP o desde
un cursor VFP y realizar una rutina para llenar los datos del cubo.
Lo primero que se debe
hacer es poner la propiedad AutoYield del objeto _VFP en falso para que el
Dynamicube funcione bien, (esto sólo es necesario en el modo Unbound). Esto lo
podemos hacer en el evento INIT del Dynamicube:
_Vfp.AutoYield=
.F.
Luego debemos poner la
propiedad DCConnectType en modo
Unbound y la propiedad AutoDataRefresh
en falso, lo último es para evitar que el DynamiCube intente cargar datos
cuando se crea el control y se muestre un mensaje de advertencia cuando se
ejecuta el formulario, esto es debido a que aún no se han creado los campos.
Esto se puede hacer desde la ventana de propiedades de Visual FoxPro o mediante
código en el evento Init del control oleCube:
This.DCConnectType= 99 && Modo Unbound.
This.AutoDataRefresh=
.F. && Evite que se muestre el
mensaje de advertencia.
También, si deseamos
tener los encabezados con letras azules y fondo verde claro, lo hacemos desde
la ventana de propiedades del DynamiCube:
Los cuales equivalen a
las propiedades FieldsForecolor y FieldsBackColor, lo que también se puede
hacer mediante programación, naturalmente que en esta última forma se pueden
especificar muchos más colores que los disponibles en la ventana de propiedades,
pero lo que se debe saber es el valor numérico equivalente al color deseado.
En este ejemplo vamos a
usar la tabla DATOS.DBF, ya creada, la cual vamos a agregarla al entorno de
datos del formulario. No es necesario que sea una tabla, en aplicaciones
reales, sería un cursor generado desde un SELECT-SQL y que tenga datos
no-normalizados, similares a los necesarios para un reporte. La tabla que vamos
a usar tiene los siguientes datos:
Luego se va a armar la
distribución de los campos, con sus encabezados, en el evento Init del formulario de la siguiente
forma:
** Crear los campos
del DynamiCube.
With This.oleCube.Fields
.DeleteAll() && Borra
todos los campos (si existe alguno).
.Add(
"division", "División", 2) && División como fila.
.Add(
"region", "Región", 1)
&& Región como columna.
.Add(
"ganancia", "Ganancia", 3)
&& Ganancia como datos.
EndWith
Una vez que se han
definido los campos, lo único que queda por hacer para completar la
configuración, o mejor dicho, la construcción del cubo, es llenar con los datos
de la tabla que se acaba de mencionar. Esto se realiza a través del evento
FetchData del DynamiCube, este evento sólo se dispara en modo Unbound y cuando
se ejecuta el método RefreshData():
Local lnCampos, laDatos( 1)
lnCampos= 3 && Número
de campos en DynamiCube.
Dimension laDatos( lnCampos)
Select Datos
Scan
** Llena los valores de los campos en el arreglo ‘laDatos’.
laDatos(
1)= Datos.division
laDatos(
2)= Datos.region
laDatos(
3)= Datos.ganancia
** Agrega los datos al DynamiCube.
This.AddRowEx( @laDatos)
EndScan
Los valores que
contiene el arreglo laDatos deben estar en el mismo orden en que se crearon los
campos, de lo contrario, se pueden obtener resultados extraños. Se usa el
método AddRowEx() para agregar al DynamiCube los datos que se encuentran en el
arreglo.
Ahora lo último que
falta para poder mostrar los datos es usar el método RefreshData(), el cual, al
ser llamado, ejecutará el código que se encuentra en el evento FetchData(). En
nuestro ejemplo se ha usado un botón que llama al método RefreshData() para
mostrar el DynamiCube:
This.Parent.oleCube.RefreshData()
El formulario queda
así:
Se pueden mover los
campos de tal manera que el DynamiCube quede así:
O así:
Para tener una vista preliminar
de cómo se imprimiría el cubo se usa el método PrintPreview(), al formulario
del ejemplo se le ha agregado un botón ‘Vista preliminar’ el cual llama a dicho
método de la siguiente manera:
This.Parent.oleCube.PrintPreview()
Lo cual mostrará una
ventana como la siguiente:
En la parte superior de
la ventana hay botones desde los cuales se puede Imprimir, configurar la
impresora y el tamaño de página, cambiar el ancho y alto de las celdas, avanzar
de página si es necesario y por último hacer un Zoom de la vista preliminar.
Si se desea imprimir el
cubo sin hacer una vista previa se usa el método Print() el cual necesita tres
parámetros: el primero si es .T. (verdadero), indica que se desea mostrar una
ventana de diálogo de impresión que permite cambiar la impresora
predeterminada, si es .F. (falso) no se muestra el diálogo y comienza a
imprimir directamente. Los dos restantes parámetros también son obligatorios e
indican el primera y última página que se van a imprimir, si se pone -1 en el
tercer parámetro, indica que se desea imprimir todas las páginas, estos
parámetros son obviados si el primer parámetro es .T. (verdadero). Para llamar
al método Print() en el botón, se haría de la siguiente forma:
This.Parent.oleCube(
.F., 1, -1)
Lo cual comenzaría
inmediatamente a imprimir en la impresora predeterminada en ese momento.
Para terminar, quiero
decir que el DynamiCube puede ser expandido para incluir más dimensiones y más
información de resumen. Provee información de soporte de decisión en un formato
flexible que los usuarios finales pueden manipular y modificar de acuerdo a sus
necesidades de análisis.
Otra de las ventajas es
que no se necesita de un servidor OLAP o similar para tener la misma funcionalidad
y lo bueno es que solo es cuestión de pegar el control en un formulario y
programarlo, tarea que se puede simplificar enormemente si se crea una clase
que ya tenga toda la funcionalidad descrita, lo cual solo haga necesario
indicar los campos, encabezados, distribución y nada más, la clase se
encargaría de todo. Por ejemplo, yo he creado una clase que uso en las
aplicaciones que desarrollo que permite mostrar el cubo, tener una vista
preliminar, imprimirlo y hasta exportarlo a una hoja Excel. Todo eso es posible
debido a que el modelo de objetos es completo y da un gran control sobre cada
aspecto del cubo.
La versión actual del DynamiCube
es la 2.5.1.2. y hay una nueva versión que es llamada ActiveCube 3 la cual es
también una gran herramienta e incluso soporta exportación a Excel en forma
nativa, la principal desventaja, si se le puede llamar así, es que solamente
soporta conectarse con servicios OLAP y aunque tiene un modo Unbound, de lo que he investigado, no se
puede hacer lo mismo que con el DynamiCube. Para los interesados, pueden
descargar la versión de evaluación desde http://www.datadynamics.com, lo
bueno es que las versiones de evaluación son completamente funcionales pero sólo
duran 30 días. Sin embargo, vale la pena investigar más a fondo este control
que es muy versátil.
FoxPress – Septiembre de 2003