¡Subscríbete! |
En esta revista se publicaron sendos artículos de Antonio Muñoz de Burgos en Julio-Agosto de 1996 y aunque siguen estando vigentes su uso es con el _GENGRAPH que invoca al asistente de gráficos. Ahora, al tener el MS Graph 5.0 u 8.0, el proceso ha cambiado ligeramente.
Crear un chart en Visual FoxPro es realmente un proceso que se realiza en dos pasos:
Antes de que empieces, asegúrate de que tienes instalado el Microsoft Graph 8.0 pues los ejemplos los vamos a hacer con él. Esto lo puedes ver en el Registry en el apartado HKEY_LOCAL_MACHINE\SOFTWARE\Classes\MSGraph. Una vez localizada, asegúrate de que tienes la versión 8.0.
Crear un nuevo gráfico
El asunto que más desconcierta es que el punto de partida tiene que ser un gráfico ya creado. O sea, que para crear un gráfico tenemos que basarnos en otro. Bien, reconozco que esto parece una contradicción pero veremos ahora como se subsana.
Una vez que ya hemos creado el gráfico (o usamos el anterior) le pasamos los nuevos datos, le cambiamos o actualizamos el formato y ya está.
Aunque Microsoft Graph soporta ActiveX Automation, no tiene ningún método que te permita pasarle los datos, esto es, no puedes manipular lo que vienen en llamar el Microsoft Graph datasheet. ¿Por qué es así? Tal vez Bill lo sepa pero esperemos que en alguna futura versión lo solucionen pues es una importante limitación. Mientras tanto, Visual FoxPro ofrece una solución que requiere pasar la estructura de los datos a un Microsoft Graph que se encuentre ya en un campo General.
Esto significa que se deben usar campos generales para crear gráficos. No hay forma programática de crear un OleControl en un formulario y pasarle los datos. Deberías usar el objeto OleBoundControl. Otra importante limitación es la forma cómo se intercambian los datos de una serie a otra (por fila o por columna), pero la forma de solucionarlo lo veremos más adelante.
Pasar Datos con APPEND GENERAL ... DATA
¿Por donde empezamos? Bueno, pues el primer paso es crear una tabla con un campo general en el que esté embebido Microsoft Graph. Como hemos comentado antes la única forma de pasar datos a un chart es a través de un campo General. La razón es que Microsoft Graph es un applet y no un Servidor ActiveX y por tanto no genera archivos.
Para hacer esto tenemos el modelo:
APPEND GENERAL GeneralFieldName DATA (cExpression)
por tanto podemos escribir:
create cursor testgen (genfld1 g) append blank append general genfld1 ; class "msgraph.Chart.8" data ; MCGDATA
No obstante, si te has apresurado a ejecutar el ejemplo anterior verás que te da error pues todavía no hemos definido el MCGDATA. El siguiente paso es añadir los datos.
La expresión de Data toma el modelo del Clipboards en que los datos de las columnas están separados por Tabs (CHR(9)) y las filas por saltos de carro y líneas en blanco (CHR(13)+CHR(10)). La siguiente tabla se puede pasar a un campo General de la forma que sigue:
1 Ctr 2 Ctr 3Ctr 4Ctr Este 20.4 27.4 90 20.4 Oeste 30.6 38.6 34.6 31.6 Norte 45.9 46.9 45 43.9 #DEFINE TAB CHR(9) #DEFINE CRLF CHR(13)+CHR(10) MCGDATA = ''+TAB+'1 Ctr'+TAB+'2 ; Ctr'+TAB+'3 Ctr'+TAB+'4 Ctr'+CRLF+; 'Este'+TAB+'20.4'+TAB+'27.4'+TAB+; '90'+ TAB+'20.4'+CRLF+; 'Oeste'+TAB+'30.6'+TAB+'38.6'; +TAB+'34.6'+TAB+'31.6'+CRLF+; 'Norte'+TAB+'45.9'+TAB+'46.9'+; TAB+'45'+TAB+'43.9' create cursor testgen (genfld1 g) append blank append general genfld1 ; class "msgraph.Chart.8" data ; MCGDATA
Este código ya sí que nos funcionará correctamente (no dará errores) aunque de momento visualmente no se ve nada. Si queremos empezar a ver resultados bastará con que ejecutemos el siguiente programa:
**************** Programa 1*************** #DEFINE TAB CHR(9) #DEFINE CRLF CHR(13)+CHR(10) MCGDATA = ''+TAB+'1 Ctr'+TAB+'2 ; Ctr'+TAB+'3 Ctr'+TAB+'4 Ctr'+CRLF+; 'Este'+TAB+'20'+TAB+'27'+TAB+; '90'+ TAB+'20'+CRLF+; 'Oeste'+TAB+'30'+TAB+'38'; +TAB+'34'+TAB+'31'+CRLF+; 'Norte'+TAB+'45'+TAB+'46'+; TAB+'45'+TAB+'43' create cursor testgen (genfld1 g) append blank append general genfld1 ; class "msgraph.Chart.8" data ; MCGDATA oForm = createobject("Form") with oForm .height = 400 .width = 600 .addobject("miGraph","OleBoundControl") with .miGraph .height = oForm.height - 20 .width = oForm.width .left = 0 .top = 0 .ControlSource = "testgen.Genfld1" .ChartType=51 .visible = .T. .refresh endwith endwith oform.visible=.T. READ EVENTS
que veríamos según el gráfico de la página anterior.
De todo lo que hemos usado en el código anterior creo que casi todo es conocido. Si queremos escoger distintos tipos de gráfico bastará con que juguemos con la propieda Chartype
Sería un poco largo enumerar todos los valores y los diversos formatos de gráficos que se pueden ver. A mí el que más me gusta es el que tiene la propiedad Chartype a 98 y se visualiza de la forma como se ve en el gráfico.
Aunque con el siguiete código podrías ver un efecto mejor:
************** Programa 2*********** #define xlBubble3DEffect 87 #DEFINE TAB CHR(9) #DEFINE CRLF CHR(13)+CHR(10) create cursor test (degree i, seno ; n(8,4) NULL, coseno n(8,4)) for ix = 1 to 90 insert into test values ; (ix,cos(ix)*ix,sin(ix)*ix) endfor 45 scan next 30 replace seno with .null. endscan wait window nowait "Cargando..." MCGDATA = "" nCols = fcount() for ix = 1 to nCols MCGDATA = MCGDATA + ; iif(empty(MCGDATA),"",; TAB)+field(ix) endfor MCGDATA = MCGDATA + CRLF scan for ix = 1 to nCols MCGDATA = MCGDATA + ; iif(ix=1,"",TAB)+nvl; (str(evaluate(field(ix))),"") endfor MCGDATA = MCGDATA + CRLF endscan create cursor testgen (genfld1 g) append blank append general genfld1 class ; "msgraph.Chart.8" data MCGDATA oForm = createobject("Form") with oForm .height = 400 .width = 600 .addobject("myGraph","OleBoundControl") with .myGraph .height = oForm.height - 20 .width = oForm.width .left = 0 .top = 0 .ControlSource = "testgen.Genfld1" .hastitle = .t. .haslegend = .t. .ChartTitle.caption = "Título del Chart" .object.application.plotby = 2 .ChartType= xlBubble3DEffect .visible = .T. .refresh endwith endwith oform.visible=.T. read events
Ordenando por fila o columna
Hasta la llegado de MS graph 8 esto no era posible pero esta nueva versión ha aportado la propiedad PlotBy que nos permite establecer esto.
Otro aspecto a tener en cuenta es que Microsoft Graph esta limitado a 256 series, y por tanto si tienes más de 256 registros que deben ser mostrados se debería usar Series Por Columna.
************Programa 3******************** * Crea una tabla con un campo general y un * gráfico close all erase migraph.dbf IF ! FILE("migraph.dbf") CREATE TABLE migraph (graph_fld G) graph_var = " " + chr(9) + ; "Resultados" + chr(13) + chr(10) ; + "Tipo 1" + chr(9) + "5" + chr(13); + chr(10) + "Tipo 2" ; + chr(9) + "10" + chr(13) + chr(10) APPEND BLANK APPEND GENERAL graph_fld CLASS ; "MsGraph.Chart" DATA graph_var ELSE IF ! USED("migraph") USE migraph IN 0 ENDIF ENDIF PUBLIC oForm oForm = CREATEOBJECT("form") oForm.ADDOBJECT("Ole1","OleBoundControl") oForm.ADDOBJECT("Command1","MyCommand") oForm.Ole1.ControlSource = ; "migraph.graph_fld" oForm.height=350 oForm.width=520 oForm.Caption = "MiGraph" oForm.Ole1.Height = 300 oForm.Ole1.Width = 500 oForm.Ole1.HasTitle = .T. oForm.Ole1.ChartTitle.Caption = "Chart ; que muestra por fila o por columna" oForm.Ole1.ChartTitle.Font.Name = "Arial" oForm.Ole1.ChartTitle.Font.Size = 12 oForm.Ole1.ChartTitle.Font.Bold = .T. oForm.Ole1.Type = 3 oForm.Visible=.t. oForm.Ole1.Visible=.t. oForm.Command1.Visible=.t. oForm.Ole1.Object.Application.PlotBy=1 DEFINE CLASS MyCommand AS COMMANDBUTTON Caption = 'Mostrar por Columna' Visible = .T. Left = 200 Top = 290 Height = 30 Width = 125 PROCEDURE Click IF oForm.Ole1.Object.; Application.PlotBy = 1 oForm.Ole1.Object.; Application.PlotBy = 2 oForm.Command1.; Caption = 'Mostrar ; por Fila' ELSE oForm.Ole1.Object.; Application.PlotBy = 1 oForm.Command1.; Caption = 'Mostrar ; por Columna' ENDIF Thisform.Refresh ENDDEFINE
Visualizar varios gráficos de forma dinámica
Otra de las cosas más frecuentes es la forma de visualizar varios gráficos con diferentes periodos de forma simultanea, algo parecido a lo que se muestra en el siguiente gráfico
El funcionamiento es muy similar al de los ejemplos que hemos puesto anteriormente.
Cada vez que se pulsa en una de las teclas navegacionales se ejecuta el código siguiente (adjunto el correspondiente a siguiente)
ThisForm.LockScreen = .T. Skip 1 If EOF() Go Bottom Endif ThisForm.ClearGraph ThisForm.ChangeQtrChart ThisForm.ChangeYearChart ThisForm.LockScreen = .F. Thisform.refresh
Los métodos de ChangeQtrChart y ChangeYearChart son los que me actualizan cada uno de los gráficos con un código como el siguiente (se adjunta solo la parte principal del código)
SELECT Employee.emp_id, RIGHT(STR(YEAR; (Orders.order_date)),2)+ ; ALLTRIM(STR(INT((MONTH; (Orders.order_date)-1)/3); +1)) AS qtr,; sum(Orders.order_amt); as qTotal; FROM testdata!employee ; INNER JOIN testdata!orders ; ON Employee.emp_id = Orders.emp_id; Where Employee.emp_id = sID ; and (Year(Orders.; order_date)= myear ; OR Year(Orders.order_date)= myear -1); GROUP BY qtr; ORDER BY qtr into cursor tmpqtr * Establece el título para el gráfico sTitle = "Quarterly Sales ; for "+ alltrim(employee.first_name)+ ; " "+alltrim(employee.last_name) ThisForm.oGraphQtr.Application.; DataSheet.Range("01").value =; Employee.Last_name iCol = 2 select tmpqtr * Hace un loop a través del cursor scan sqtr = left(tmpQtr.qtr,2)+" Qtr "+; right(alltrim(tmpQtr.qtr),1) ThisForm.oGraphQtr.Application.; DataSheet.cells(1,iCol).; value = sqtr ThisForm.oGraphQtr.Application.; DataShe et.cells(2,iCol).; value = tmpQtr.qTotal iCol = iCol+1 endscan * Muestra el titulo del gráfico ThisForm.oGraphQtr.HasTitle = .T. ThisForm.oGraphQtr.ChartTitle.; Text = sTitle
Algunas Peculiaridades
¿Cómo guardar un gráfico en otra tabla?. Seguramente querás seguir manteniendo intacta tu plantilla de gráficos y el nuevo gráfico guardarlo en algún sitio. Para esto podemos acudir a las posibilidades del INSERT INTO. En el código que hay a continuación se ve como creamos una nueva tabla llamada Migraphs y guardamos el nuevo campo general de la siguiente forma:
CREATE TABLE migraphs FREE (olechart g) INSERT INTO (DBF()) VALUE(graphdbf.graphfld)
Sin embargo, te puede sorprender ver que las cosas no son siempre como parecen. Aunque la automatización funciona si se te ocurre ver ese campo general verás que no se muestra correctamente esto nos quiere decir que antes de copiar el campo necesitamos forzar la actualización de la información del campo lo cual se hace simplemente con.
oGraphRef = "" oGraphform = ""
El asistente de Gráficos de Visual FoxPro
Muchos dolores de cabeza se quitan usando este asistente. Información sobre el mismo y un ejemplo excelente se muestran en el artículo de Antonio Muñoz que se ha reseñado al principio.
Las Constantes
Como puede que cuando ‘entréis’ en este tema necesitaréis las constantes para cada uno de las propiedades, las tenéis en el documento 189265 que si al editor de la revista no se le olvida las meterá entre los ficheros de este mes. También hay un gráfico, bastante grande, que muestra todas las propiedades y métodos de los que se compone el objeto el MS graph
Alberto Rodriguez. Se puede entrar en contacto con él en alb@fpress.com
Por Alberto Rodríguez
© Copyright 1998 by FoxPress, All rights reserved
FoxPress, Diciembre de 1998