- Gráficas de barra sin complicaciones
- Traducción: http://comunidadvfp.blogspot.com/2006/08/graficas-de-barra-sin-complicaciones.html
- Original: http://weblogs.foxite.com/vfpimaging/2006/03/21/bar-graphics-without-complications/
y
- Gráficas de tarta con código VFP puro
- Traducción: http://comunidadvfp.blogspot.com/2006/08/graficas-de-tarta-con-codigo-vfp-puro.html
- Original: http://weblogs.foxite.com/vfpimaging/2006/03/24/pie-graphics-with-pure-vfp-code/
El objetivo de este artículo es tener otra opción (siempre VFP nos da esta posibilidad) de generar gráficas con solo el uso del objeto Shape, sin depender del uso de ninguna otra herramienta de terceras partes.
La idea
Con el uso del objeto Shape es fácil crear barras rectangulares configurando las propiedades Width (ancho) y Height (alto) con las dimensiones correspondientes, según la cantidad de barras del gráfico y el valor a graficar. El tema aquí es como graficar las distintas porciones de una torta (sección circular) o las secciones de un anillo con este objeto.A partir de Visual FoxPro 9.0, disponemos de la nueva propiedad PolyPoints en el objeto Shape (también en el objeto Line), que nos permiten graficar formas poligonales (ver el artículo Dibujando polígonos con VFP 9.0). Con esta técnica, graficaremos cada porción como un polígono con sus respectivas dimensiones, e iremos añadiendo las restantes porciones hasta completar la gráfica como se observa en las figuras siguientes.
Nota: Las opciones del tipo de gráfica torta, anillo y cono, solo se podrá ejecutar en la versión 9.0 de Visual FoxPro, por el uso de la propiedad PolyPoints de los objetos Shapes.
La clase
Como mencioné al principio de estas líneas, mi objetivo es generar gráficas con código VFP puro, para ello he creado una clase a partir de un objeto Container, al que se irán agregando en tiempo de ejecución los objetos Shape para formar la gráfica y también se agregaran las correspondientes leyendas. Su uso es muy fácil, y solo de deben configurar 5 propiedades y ejecutar el método GenerarGrafica() como se expone en las siguientes líneas de código:
WITH THISFORM.lmGraph .TipoGrafica = 1 && Anillo .TipoLeyenda = 3 && Rótulos .TipoColor = 0 && Aleatorios .TituloGrafica = "Consumos por mes" .Alias = "MiTabla" .GenerarGrafica() ENDWITHLas propiedades de la clase y sus valores son los siguientes:
- TipoGrafica: 0=Torta, 1=Anillo, 2=Barras verticales, 3=Barras horizontales, 4=Conos verticales, y 5=Conos horizontales
- TipoLeyenda: 0=Sin leyendas, 1=Valores, 2=Porcentajes, 3=Rótulos, 4=Rótulos y valores, y 5=Porcentajes y rótulos
- TipoColor: 0=Aleatorios y 1=Colores básicos (28 colores definidos)
- TituloGrafica: Cadena con el título superior de la gráfica
- Alias: Alias de la tabla o cursor que contiene los rótulos y valores a graficar
- 1° Campo: Este campo contiene los valores y debe ser Numérico.
- 2° Campo: Este campo contiene los rótulos y puede ser de tipo Caracter, Date, DateTime o Numérico.
Los ejemplos
Ejecutando el formulario de ejemplo con la clase incluida, podemos lograr gráficas simples y agradables como lo muestran las figuras siguientes:Gráfica de torta, con leyenda de porcentajes y rótulos, y colores aleatorios
Gráfica de anillo, con leyenda de rótulos y valores, y colores básicos
Gráfica de barras verticales, con leyenda de rótulos, y colores aleatorios
Gráfica de barras horizontales, sin leyenda, y colores básicos
Gráfica de conos verticales, con leyenda de porcentajes, y colores aleatorios
Gráfica de conos verticales, con leyenda de valores, y colores aleatorios
El formulario del ejemplo tiene una casilla de verificación (DEMO) que marcada, generará aleatoria y automáticamente cada 2 segundos, las distintas combinaciones posibles para cada una de las propiedades de la clase.
El código
El siguiente es el código del formulario de ejemplo y la clase para generar las gráficas:
PUBLIC goForm goForm = CREATEOBJECT("frmEjemplo") goForm.SHOW RETURN *-- *-- Definición del formulario de ejemplo *-- DEFINE CLASS frmejemplo AS FORM HEIGHT = 431 WIDTH = 496 SHOWWINDOW = 2 AUTOCENTER = .T. CAPTION = "Gráficas con VFP9" ICON = (HOME(4) + "icons\office\graph11.ico") NAME = "frmEjemplo" ADD OBJECT tmr AS TIMER WITH ; ENABLED = .F., INTERVAL = 2000, NAME = "tmr" ADD OBJECT opgColores AS OPTIONGROUP WITH ; BUTTONCOUNT = 2, ANCHOR = 6, VALUE = 1, ; HEIGHT = 48, LEFT = 344, TOP = 280, WIDTH = 136, ; TABINDEX = 4, NAME = "opgColores", ; Option1.BACKSTYLE = 0, Option1.CAPTION = "Colores aleatorios", ; Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ; Option1.WIDTH = 120, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ; Option2.BACKSTYLE = 0, Option2.CAPTION = "Colores básicos", ; Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ; Option2.WIDTH = 109, Option2.AUTOSIZE = .T., Option2.NAME = "Option2" ADD OBJECT cmdGenerar AS COMMANDBUTTON WITH ; TOP = 392, LEFT = 376, HEIGHT = 32, WIDTH = 104, ; ANCHOR = 6, WORDWRAP = .T., CAPTION = "Generar gráfica", ; TABINDEX = 9, NAME = "cmdGenerar" ADD OBJECT opgGraficas AS OPTIONGROUP WITH ; BUTTONCOUNT = 6, ANCHOR = 6, VALUE = 1, ; HEIGHT = 112, LEFT = 16, TOP = 280, WIDTH = 144, ; TABINDEX = 2, NAME = "opgGraficas", ; Option1.BACKSTYLE = 0, Option1.CAPTION = "Torta", ; Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ; Option1.WIDTH = 46, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ; Option2.BACKSTYLE = 0, Option2.CAPTION = "Anillo", ; Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ; Option2.WIDTH = 48, Option2.AUTOSIZE = .T., Option2.NAME = "Option2", ; Option3.BACKSTYLE = 0, Option3.CAPTION = "Barras verticales", ; Option3.HEIGHT = 17, Option3.LEFT = 8, Option3.TOP = 40, Option3.WIDTH = 110, ; Option3.AUTOSIZE = .T., Option3.NAME = "Option3", ; Option4.BACKSTYLE = 0, Option4.CAPTION = "Barras horizontales", ; Option4.HEIGHT = 17, Option4.LEFT = 8, Option4.TOP = 56, Option4.WIDTH = 125, ; Option4.AUTOSIZE = .T., Option4.NAME = "Option4", ; Option5.BACKSTYLE = 0, Option5.CAPTION = "Conos verticales", ; Option5.HEIGHT = 17, Option5.LEFT = 8, Option5.TOP = 72, Option5.WIDTH = 110, ; Option5.AUTOSIZE = .T., Option5.NAME = "Option5", ; Option6.BACKSTYLE = 0, Option6.CAPTION = "Conos horizontales", ; Option6.HEIGHT = 17, Option6.LEFT = 8, Option6.TOP = 88, Option6.WIDTH = 125, ; Option6.AUTOSIZE = .T., Option6.NAME = "Option6" ADD OBJECT opgLeyendas AS OPTIONGROUP WITH ; BUTTONCOUNT = 6, ANCHOR = 6, VALUE = 6, ; HEIGHT = 112, LEFT = 176, TOP = 280, WIDTH = 152, ; TABINDEX = 3, NAME = "opgLeyendas", ; Option1.BACKSTYLE = 0, Option1.CAPTION = "Sin leyendas", ; Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, Option1.WIDTH = 89, ; Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ; Option2.BACKSTYLE = 0, Option2.CAPTION = "Valores", ; Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, Option2.WIDTH = 60, ; Option2.AUTOSIZE = .T., Option2.NAME = "Option2", ; Option3.BACKSTYLE = 0, Option3.CAPTION = "Porcentajes", ; Option3.HEIGHT = 17, Option3.LEFT = 8, Option3.TOP = 40, Option3.WIDTH = 84, ; Option3.AUTOSIZE = .T., Option3.NAME = "Option3", ; Option4.BACKSTYLE = 0, Option4.CAPTION = "Rótulos", ; Option4.HEIGHT = 17, Option4.LEFT = 8, Option4.TOP = 56, Option4.WIDTH = 61, ; Option4.AUTOSIZE = .T., Option4.NAME = "Option4", ; Option5.BACKSTYLE = 0, Option5.CAPTION = "Rótulos y valores", ; Option5.VALUE = 0, Option5.HEIGHT = 17, Option5.LEFT = 8, Option5.TOP = 72, ; Option5.WIDTH = 112, Option5.AUTOSIZE = .T., Option5.NAME = "Option5", ; Option6.BACKSTYLE = 0, Option6.CAPTION = "Porcentajes y rótulos", ; Option6.VALUE = 1, Option6.HEIGHT = 17, Option6.LEFT = 8, Option6.TOP = 88, ; Option6.WIDTH = 133, Option6.AUTOSIZE = .T., Option6.NAME = "Option6" ADD OBJECT lmGraph AS lmgraph WITH ; ANCHOR = 15, TOP = 8, LEFT = 8, WIDTH = 480, HEIGHT = 264, ; TABINDEX = 1, NAME = "lmGraph", lbl.NAME = "lbl" ADD OBJECT chk AS CHECKBOX WITH ; TOP = 404, LEFT = 304, HEIGHT = 17, WIDTH = 53, ANCHOR = 6, ; WORDWRAP = .T., AUTOSIZE = .T., ALIGNMENT = 0, BACKSTYLE = 0, ; CAPTION = "DEMO", VALUE = .F., TABINDEX = 8, NAME = "chk" ADD OBJECT opgDatos AS OPTIONGROUP WITH ; BUTTONCOUNT = 2, ANCHOR = 6, VALUE = 1, HEIGHT = 48, ; LEFT = 344, TOP = 336, WIDTH = 136, TABINDEX = 5, NAME = "opgDatos", ; Option1.BACKSTYLE = 0, Option1.CAPTION = "Ejemplo semanal", ; Option1.VALUE = 1, Option1.HEIGHT = 17, Option1.LEFT = 8, Option1.TOP = 8, ; Option1.WIDTH = 116, Option1.AUTOSIZE = .T., Option1.NAME = "Option1", ; Option2.BACKSTYLE = 0, Option2.CAPTION = "Ejemplo anual", ; Option2.VALUE = 0, Option2.HEIGHT = 17, Option2.LEFT = 8, Option2.TOP = 24, ; Option2.WIDTH = 98, Option2.AUTOSIZE = .T., Option2.NAME = "Option2" ADD OBJECT lblTitulo AS LABEL WITH ; AUTOSIZE = .T., ANCHOR = 6, BACKSTYLE = 0, CAPTION = "Título", ; HEIGHT = 17, LEFT = 16, TOP = 404, WIDTH = 32, TABINDEX = 6, NAME = "lblTitulo" ADD OBJECT txtTitulo AS TEXTBOX WITH ; ANCHOR = 6, VALUE = "TOTAL DE VENTAS", HEIGHT = 23, LEFT = 56, ; TABINDEX = 7, TOP = 400, WIDTH = 232, NAME = "txtTitulo" PROCEDURE GenerarCursor LPARAMETERS tnDatos CREATE CURSOR MiCursor (Valor N(10,2), Rotulo C(20)) IF tnDatos = 1 INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Lunes") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Martes") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Miércoles") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Jueves") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Viernes") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Sábado") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Domingo") ELSE INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Enero") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Febrero") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Marzo") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Abril") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Mayo") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Junio") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Julio") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Agosto") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Setiembre") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Octubre") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Noviembre") INSERT INTO MiCursor VALUES (RAND() * 1000 + 250, "Diciembre") ENDIF ENDPROC PROCEDURE tmr.TIMER THISFORM.opgGraficas.VALUE = CEILING(RAND()*6) THISFORM.opgLeyendas.VALUE = CEILING(RAND()*6) THISFORM.opgColores.VALUE = CEILING(RAND()*2) THISFORM.opgDatos.VALUE = CEILING(RAND()*2) THISFORM.txtTitulo.VALUE = IIF(THISFORM.opgDatos.VALUE = 1, ; "Total de ventas por día", "Total de ventas por mes") THISFORM.cmdGenerar.CLICK ENDPROC PROCEDURE cmdGenerar.CLICK WITH THISFORM.lmGraph .TipoGrafica = THISFORM.opgGraficas.VALUE - 1 .TipoLeyenda = THISFORM.opgLeyendas.VALUE - 1 .TipoColor = THISFORM.opgColores.VALUE - 1 .ALIAS = "MiCursor" .TituloGrafica = ALLTRIM(THISFORM.txtTitulo.VALUE) THISFORM.GenerarCursor(THISFORM.opgDatos.VALUE) .GenerarGrafica() ENDWITH ENDPROC PROCEDURE chk.VALID IF THIS.VALUE THISFORM.tmr.TIMER ENDIF THISFORM.SETALL("Enabled", NOT THIS.VALUE, "CommandButton") THISFORM.SETALL("Enabled", NOT THIS.VALUE, "OptionGroup") THISFORM.SETALL("Enabled", NOT THIS.VALUE, "TextBox") THISFORM.tmr.ENABLED = THIS.VALUE ENDPROC ENDDEFINE *-- *-- Definición de la clase lmGraph *-- DEFINE CLASS lmgraph AS CONTAINER WIDTH = 200 HEIGHT = 100 SPECIALEFFECT = 1 BACKCOLOR = RGB(255,255,255) ALIAS = "" TipoLeyenda = 5 TipoColor = 0 TipoGrafica = 0 TituloGrafica = "Título" NAME = "lmgraph" ADD OBJECT lbl AS LABEL WITH ; AUTOSIZE = .T., FONTBOLD = .T., BACKSTYLE = 0, ; CAPTION = "lmGraph v.1.0", HEIGHT = 17, LEFT = 8, ; TOP = 8, VISIBLE = .F., WIDTH = 79, NAME = "lbl" *-- Genera la Gráfica PROCEDURE GenerarGrafica LOCAL lcCampoRotulo, lcCampo, lnSaltoH, lnSaltoV, lnReg, ; lnTotal, lnCantReg, lnMaximo, lnMaxWidth, lcRotulo, lnValor, lnPorc, ; lcObjPor, lcObjShp, lcObjLey, lnDim, lnHasta, ; lnI, lnJ, lnAng, lnCos, lnSen, lcObj1, lcObj2 *-- *-- Limpio los objetos del gráfico *-- THIS.LimpiarGrafica() *--- *--- Verifico la versión de VFP y tipo de gráfica *--- IF VERSION(5) < 900 AND INLIST(THIS.TipoGrafica, 0, 1, 4, 5) MESSAGEBOX("El tipo de gráfica seleccionada no esta disponible para" + ; CHR(13) + VERSION(), 48, "lmGraph") RETURN ENDIF *-- *-- Tabla de datos *-- IF EMPTY(THIS.ALIAS) MESSAGEBOX("No especificó la propiedad Alias.", 48, "lmGraph") RETURN ENDIF IF NOT USED(THIS.ALIAS) MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ; " no está en uso.", 48, "lmGraph") RETURN ENDIF IF AFIELDS(la,THIS.ALIAS) < 2 MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ; " tiene menos de dos campos.", 48, "lmGraph") RETURN ENDIF IF NOT INLIST(la(1,2), "N", "I") MESSAGEBOX("El segundo campo de la tabla " + PROPER(THIS.ALIAS) + ; " no es numérico.", 48, "lmGraph") RETURN ENDIF SELECT (THIS.ALIAS) lcCampoValor = la(1,1) lcCampoRotulo = la(2,1) CALCULATE COUNT() TO lnCantReg IF lnCantReg = 0 MESSAGEBOX("La tabla " + PROPER(THIS.ALIAS) + ; " no contiene datos.", 48, "lmGraph") RETURN ENDIF CALCULATE SUM(EVALUATE(lcCampoValor)) TO lnTotal CALCULATE MAX(EVALUATE(lcCampoValor)) TO lnMaximo *-- *-- Variables y área del gráfico *-- #DEFINE AnguloPrimerSector 270 #DEFINE AngulosParaGraficar 360 lnAnguloSector = AnguloPrimerSector lnLeft = 10 lnTop = IIF(EMPTY(THIS.TituloGrafica),10,30) lnWidth = THIS.WIDTH - lnLeft * 2 lnHeight = THIS.HEIGHT - lnTop - lnLeft lnSaltoH = FLOOR(lnHeight / lnCantReg) *-- *-- Titulo del gráfico *-- IF NOT EMPTY(THIS.TituloGrafica) && Con título THIS.ADDOBJECT("lblTitulo","Label") WITH THIS.lblTitulo .BACKSTYLE = 0 .ALIGNMENT = 2 .FONTSIZE = 12 .FONTBOLD = .T. .CAPTION = THIS.TituloGrafica .TOP = 5 .LEFT = lnLeft .WIDTH = lnWidth .HEIGHT = 30 ENDWITH ENDIF *-- *-- Armo leyenda y tomo el ancho *-- IF THIS.TipoLeyenda # 0 && Con leyenda lnMaxWidth = 0 lnReg = 1 SCAN ALL lcRotulo = ALLTRIM(TRANSFORM(EVALUATE(lcCampoRotulo))) lnValor = EVALUATE(lcCampoValor) lnPorc = lnValor / lnTotal * 100 lcObjLey = "oLey" + TRANSFORM(lnReg) THIS.ADDOBJECT(lcObjLey,"Label") WITH THIS.&lcObjLey .TOP = lnSaltoH * lnReg - lnSaltoH + lnTop DO CASE CASE THIS.TipoLeyenda = 1 .CAPTION = TRANSFORM(lnValor) CASE THIS.TipoLeyenda = 2 .CAPTION = TRANSFORM(ROUND(lnPorc,2)) + "%" CASE THIS.TipoLeyenda = 3 .CAPTION = lcRotulo CASE THIS.TipoLeyenda = 4 .CAPTION = lcRotulo + " - " + TRANSFORM(lnValor) OTHERWISE .CAPTION = TRANSFORM(ROUND(lnPorc,2)) + "% - " + lcRotulo ENDCASE .FONTSIZE = 8 .BACKSTYLE = 0 .LEFT = lnWidth + 100 .AUTOSIZE = .T. .VISIBLE = .T. lnMaxWidth = MAX(lnMaxWidth,.WIDTH) ENDWITH lnReg = lnReg + 1 ENDSCAN lnLeftLeyenda = MAX(lnWidth * .60, lnWidth - lnMaxWidth - 40) ENDIF *-- *-- Armo el resto del gráfico *-- lnReg = 1 SCAN ALL lnValor = EVALUATE(lcCampoValor) lnPorc = lnValor / lnTotal * 100 *-- *-- Armo cada porcion *-- lcObjPor = "oPor" + TRANSFORM(lnReg) THIS.ADDOBJECT(lcObjPor,"Shape") WITH THIS.&lcObjPor DO CASE CASE THIS.TipoGrafica = 0 OR THIS.TipoGrafica = 1 && Torta/Anillo IF THIS.TipoLeyenda = 0 && Sin leyenda STORE MIN(lnWidth ,lnHeight) TO .WIDTH, .HEIGHT .TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop) .LEFT = FLOOR((lnWidth - .WIDTH) / 2 + lnLeft) ELSE STORE MIN(lnLeftLeyenda, lnHeight) TO .WIDTH, .HEIGHT .TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop) .LEFT = FLOOR((lnLeftLeyenda - .WIDTH) / 2 + lnLeft) ENDIF .POLYPOINTS = "This.aPoly" lnDim = AngulosParaGraficar * lnPorc / 100 lnHasta = CEILING(lnDim) + 1 .ADDPROPERTY("aPoly[" + TRANSFORM(lnHasta) + ",2]") STORE 50 TO .aPoly[1,1], .aPoly[1,2] FOR lnI = 2 TO lnHasta lnAng = (360 / AngulosParaGraficar) * (lnI - 2) lnCos = COS(DTOR(lnAng + lnAnguloSector)) lnSen = SIN(DTOR(lnAng + lnAnguloSector)) .aPoly(lnI,1) = 50 * lnCos + 50 .aPoly(lnI,2) = 50 * lnSen + 50 ENDFOR lnAnguloSector = lnAnguloSector + lnDim * 360 / AngulosParaGraficar CASE THIS.TipoGrafica = 2 OR THIS.TipoGrafica = 4 && Barras/Conos Verticales IF THIS.TipoLeyenda = 0 && Sin leyenda lnSaltoV = FLOOR(lnWidth / lnCantReg) ELSE lnSaltoV = FLOOR(lnLeftLeyenda / lnCantReg) ENDIF .WIDTH = lnSaltoV + 1 .LEFT = lnSaltoV * lnReg - lnSaltoV + lnLeft .HEIGHT = lnValor / lnMaximo * lnHeight .TOP = lnHeight - .HEIGHT + lnTop IF THIS.TipoGrafica = 4 && Conos .POLYPOINTS = "This.aPoly" .ADDPROPERTY("aPoly[" + TRANSFORM(4) + ",2]") STORE 0 TO .aPoly[1,1], .aPoly[2,2], .aPoly[3,2] STORE 100 TO .aPoly[1,2], .aPoly[4,1], .aPoly[4,2] .aPoly[2,1] = 30 .aPoly[3,1] = 70 ENDIF CASE THIS.TipoGrafica = 3 OR THIS.TipoGrafica = 5 && Barras/Conos Horizontales IF THIS.TipoLeyenda = 0 && Sin leyenda .WIDTH = lnValor / lnMaximo * lnWidth ELSE .WIDTH = lnValor / lnMaximo * lnLeftLeyenda ENDIF .LEFT = lnLeft .HEIGHT = lnSaltoH + 1 .TOP = lnSaltoH * lnReg - lnSaltoH + lnTop IF THIS.TipoGrafica = 5 && Conos .POLYPOINTS = "This.aPoly" .ADDPROPERTY("aPoly[" + TRANSFORM(4) + ",2]") STORE 0 TO .aPoly[1,1], .aPoly[2,1], .aPoly[2,2] STORE 100 TO .aPoly[1,2], .aPoly[3,1], .aPoly[4,1] .aPoly[3,2] = 25 .aPoly[4,2] = 75 ENDIF OTHERWISE MESSAGEBOX("Tipo de gráfica no definida.", 48, "lmGraph") RETURN ENDCASE *-- *-- Color de la porción *-- IF THIS.TipoColor = 0 .BACKCOLOR = FLOOR(RAND() * 16777216) && Aleatorio ELSE .BACKCOLOR = THIS.ColoresBasicos(lnReg) ENDIF ENDWITH *-- *-- Armo leyendas *-- IF THIS.TipoLeyenda # 0 && Con leyenda lcObjShp = "oShp" + TRANSFORM(lnReg) THIS.ADDOBJECT(lcObjShp,"Shape") WITH THIS.&lcObjShp .HEIGHT = 12 .WIDTH = 12 .BACKCOLOR = EVALUATE("THIS.oPor" + TRANSFORM(lnReg) + ".BACKCOLOR") .TOP = lnSaltoH * lnReg - lnSaltoH + lnTop .LEFT = lnLeftLeyenda + lnLeft + 10 ENDWITH lcObjLey = "oLey" + TRANSFORM(lnReg) WITH THIS.&lcObjLey .LEFT = lnLeftLeyenda + lnLeft + 30 ENDWITH ENDIF lnReg = lnReg + 1 ENDSCAN *-- *-- Anillo *-- IF THIS.TipoGrafica = 1 && Anillo THIS.ADDOBJECT("oShpMed","Shape") WITH THIS.oShpMed IF THIS.TipoLeyenda = 0 && Sin leyenda STORE MIN(lnWidth ,lnHeight) * .45 TO .WIDTH, .HEIGHT .TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop) .LEFT = FLOOR((lnWidth - .WIDTH) / 2 + lnLeft) ELSE STORE MIN(lnLeftLeyenda, lnHeight) * .45 TO .WIDTH, .HEIGHT .TOP = FLOOR((lnHeight - .HEIGHT) / 2 + lnTop) .LEFT = FLOOR((lnLeftLeyenda - .WIDTH) / 2 + lnLeft) ENDIF .BACKCOLOR = THIS.BACKCOLOR .CURVATURE = 99 ENDWITH ENDIF *-- *-- Uno porciones en Torta/Anillo *-- IF THIS.TipoGrafica = 0 OR THIS.TipoGrafica = 1 && Torta/Anillo FOR lnI = 1 TO lnCantReg - 1 lcObj1 = "This.oPor" + TRANSFORM(lnI) lcObj2 = "This.oPor" + TRANSFORM(lnI+1) lnJ = ALEN(&lcObj1..aPoly,1) &lcObj1..aPoly(lnJ,1) = &lcObj2..aPoly(2,1) &lcObj1..aPoly(lnJ,2) = &lcObj2..aPoly(2,2) ENDFOR lcObj1 = "This.oPor" + TRANSFORM(1) lnJ = ALEN(&lcObj2..aPoly,1) &lcObj2..aPoly(lnJ,1) = &lcObj1..aPoly(2,1) &lcObj2..aPoly(lnJ,2) = &lcObj1..aPoly(2,2) ENDIF *-- *-- Hago visible los objetos creados *-- THIS.SETALL("Visible",.T., "Shape") THIS.SETALL("Visible",.T., "Label") ENDPROC PROCEDURE ColoresBasicos LPARAMETERS tn LOCAL la(28) tn = MOD(tn-1,28)+1 la(1) = RGB(255,0,0) && Rojo la(2) = RGB(255,255, 0) && Amarillo la(3) = RGB(0,0,255) && Azul la(4) = RGB(0,128,0) && Verde Oscuro la(5) = RGB(255,128,0) && Anaranjado la(6) = RGB(128,64,0) && Marrón la(7) = RGB(255,0,255) && Magenta la(8) = RGB(128,0,255) && Violeta la(9) = RGB(0,255,255) && Cyan la(10) = RGB(192,192,0) && Amarillo Oscuro la(11) = RGB(192,0,0) && Rojo Oscuro la(12) = RGB(0,255,0) && Verde la(13) = RGB(0,0,128) && Azul Oscuro la(14) = RGB(255,192,0) && Anaranjado Claro la(15) = RGB(0,192,255) && Azul claro la(16) = RGB(128,128,0) && Marrón Claro la(17) = RGB(255,192,255) && Magenta Claro la(18) = RGB( 64,128,128) && Verde Azulado la(19) = RGB(255,0,128) && Fucsia la(20) = RGB(255,255,192) && Amarillo Claro la(21) = RGB(192,0,255) && Violeta Claro la(22) = RGB(192,255,192) && Verde Claro la(23) = RGB(128,0,128) && Violeta Oscuro la(24) = RGB(192,255,255) && Cyan Claro la(25) = RGB(128,128,128) && Gris Oscuro la(26) = RGB(255,255,255) && Blanco la(27) = RGB(192,192,192) && Gris la(28) = RGB(0,0,0) && Negro RETURN la(tn) ENDPROC PROCEDURE LimpiarGrafica LOCAL lnI FOR lnI = THIS.CONTROLCOUNT TO 1 STEP -1 THIS.REMOVEOBJECT(THIS.CONTROLS(lnI).NAME) ENDFOR ENDPROC PROCEDURE INIT SET TALK OFF RAND(-1) ENDPROC ENDDEFINE
La descarga
Pueden descargar el proyecto con el formulario de ejemplo y la clase lmGraph desde el enlace siguiente:
El final
Con la clase presentada en este artículo, ustedes podrán generar gráficas simples y muy fáciles de incorporar en formularios de VFP. Si necesitan gráficas mas avanzadas utilizando solo Visual FoxPro, los invito a que lean el excelente artículo de Cesar Ch. publicado en la revista UTMag y se sorprenderán de todo lo que se puede realizar con GDI+
- Gráficos en torta avanzados con GDI+
- http://www.utmag.com/wconnect/wc.dll?9,7,10,Spanish,2094
Los comentarios
Cualquier comentario que quieran realizar sobre este artículo y esta clase, será bienvenido. Solo envien sus comentario haciendo clic en el botón "Enviar comentario" al final de este artículo.
Hasta la próxima.
Luis María Guayán
¿Cómo se podría guardar, por programación, una imagen (bmp, gif, jpg) del gráfico generado?
ResponderBorrarEstimado, ¿encontraste como copiar a una imagen el gráfico generado?
BorrarLo quiero quiero llevar a mi reporte vfp.
Gracias
Lo puedes hacer con la clase GDIPlusX de Cesar Ch.
ResponderBorrarhttp://vfpx.codeplex.com/wikipage?title=GDIPlusX&ProjectName=vfpx
En tu formulario con la clase lmGraph, en el método Click de un botón Imprimir por ej:
Do System.App
local loBmp as xfcBitmap
With _Screen.System.Drawing
loBmp = .Bitmap.FromScreen(Thisform.lmGraph1) && parametro objecto lmGraph
*-- Para guardar como imagen
*loBmp.Save("c:\lmGraph.Png", .Imaging.ImageFormat.Png)
*-- Para imprimir
loBmp.ToPrinter()
EndWith
Buen día muy buen ayuda gracias
ResponderBorrarComo podría imprimir la gráfica que se genera en la clase?
En la respuesta de arriba está la solución:
ResponderBorrarLo puedes hacer con la clase GDIPlusX de Cesar Ch.
http://vfpx.codeplex.com/wikipage?title=GDIPlusX&ProjectName=vfpx
En tu formulario con la clase lmGraph, en el método Click de un botón Imprimir por ej:
Do System.App
local loBmp as xfcBitmap
With _Screen.System.Drawing
loBmp = .Bitmap.FromScreen(Thisform.lmGraph1) && parametro objecto lmGraph
*-- Para guardar como imagen
*loBmp.Save("c:\lmGraph.Png", .Imaging.ImageFormat.Png)
*-- Para imprimir
loBmp.ToPrinter()
EndWith
¿Como lo hago con la versión 6.0 ?
BorrarGracias.
Buenas tardes. como podríamos en vista previa
ResponderBorrarUna vez guardado como imagen, puedes poner en un reporte un objeto picture y referenciar el archivo generado.
Borrar