¡Subscríbete!

MS GRAPH 8.0

Explicación del uso del MS GRAPH 8.0 (viene con el Office 97) con VFP .

Por Alberto Rodríguez

E l tratamiento de los gráficos en VFP entraña algunas veces dificultades para los desarrolladores. La dificultad que en algún caso puede llegar a desesperación casi siempre viene por la falta de información sobre cómo usarlo pues por otra parte el proceso es muy sencillo. A esta dificultad inicial de falta de información se le agrava el hecho de que VFP 5.0 se publicó con el MS Graph 5.0 y un ejemplo llamado OLEGRAPH.SCX que se encuentra en el directorio /samples/solution/OLE. Aunque el ejemplo funciona correctamente, el problema viene cuando el usuario o desarrollador tiene también instalado el Office 97 o cualquiera de sus componentes pues esta herramienta de Microsoft actualiza el MS Graph a su versión 8.0 y el ejemplo que viene con VFP 5.0 deja de funcionar. Con un ejemplo que no funciona y con falta de información muy poco se puede hacer.

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:

  • 1. El primer paso traspasa los datos a Microsoft Graph.
  • 2. El Segundo usa la Automatización ActiveX para establecer los diversos atributos de un chart.

    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 ejemplo está tomado de la Base de conocimientos de MS y nos permite ver muy graficamente las distintas posibilidades que tenemos.

    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