Formularios con fondos de colores degradados con GDI+

30/03/2020

 

Autor: Cesar Ch.

Este escrito va para Bernard Bout.

Después de leer este post, vea también Gradient Backgrounds in your forms with GDI+ Part 2 (traducido al español en PortalFox como "Formularios con fondos de colores degradados con GDI+ Parte 2").


GDI+ permite crear muchos efectos tales como degradado de colores. Esta característica no se incluyó en _gdiplus.vcx; pero se puede acceder fácilmente con una única llamada a la función Flat de API. La mayor parte del código que se muestra a continuación relacionado con la brocha con Degradado es de Bob Durban.

Aplicarlo en formularios es realmente sencillo. Agregue el código que está debajo a los eventos del formulario: LOAD, RESIZE y DESTROY



Load Event

     LOCAL lcGradFile
     lcGradFile = ADDBS(SYS(2023))+SYS(2015)+".bmp"
     This.AddProperty("cTempGradFile",lcGradFile)
       IF FILE(lcGradFile)
         CLEAR RESOURCES (lcGradFile)
       ENDIF
     LOCAL lnRGBColor1
     lnRGBColor1 = RGB(60,30,180) && Blue

     * Crear la imagen para el degradado con GdipCreateLineBrushI
     SET CLASSLIB TO HOME() + "ffc/_gdiplus.vcx" ADDITIVE

     * Declarar API
     DECLARE Long GdipCreateLineBrushI IN GDIPLUS.dll ;
       String point1, String point2, ;
       Long color1, Long color2, ;
       Long wrapMode, Long @lineGradient

     * Crear un objeto color y guarda los valores de color ARGB en variables
     LOCAL loClr AS GpColor OF HOME() + "ffc/_gdiplus.vcx"
     LOCAL lnColor1, lnColor2
     loClr = CREATEOBJECT("gpColor")
     loClr.FoxRGB = lnRGBColor1
     lnColor1 = loClr.ARGB
     loClr.FoxRGB = RGB(255,255,255) && White
     lnColor2 = loClr.ARGB

     * Crear un bitmap
     LOCAL loBmp AS GpBitmap OF HOME() + "ffc/_gdiplus.vcx"
     loBmp = CREATEOBJECT("gpBitmap")
     loBmp.Create(1,Thisform.Height)

     * Obtener un objeto gráfico bitmap
     LOCAL loGfx AS GpGraphics OF HOME() + "ffc/_gdiplus.vcx"
     loGfx = CREATEOBJECT("gpGraphics")
     loGfx.CreateFromImage(loBmp)

     * Obtener una brocha con degradado
     LOCAL loBrush as GpBrush OF HOME() + "ffc/_gdiplus.vcx"
     LOCAL hBrush && Brush Handle
     hBrush = 0
     GdipCreateLineBrushI(BINTOC(0,"4rs")+BINTOC(0,"4rs"), ;
       BINTOC(0,"4rs")+BINTOC(Thisform.Height,"4rs"), ;
       lnColor1, lnColor2, 0, @hBrush)
     loBrush = CREATEOBJECT("gpBrush")
     loBrush.SetHandle(hBrush, .T.)

     * Llenar nuestro mapa de bits con el degradado
     loGfx.FillRectangle(loBrush,0,0,1,Thisform.Height)
     loBmp.SaveToFile(lcGradFile,"image/bmp")
     Thisform.AddObject("ImgBackGround","Image")
     WITH Thisform.ImgBackGround
       .Stretch = 2
       .Width = Thisform.Width
       .Height = Thisform.Height
       .Picture = lcGradFile
       .Visible = .T.
     ENDWITH
     RETURN


Resize Event

     Thisform.ImgBackGround.Width = Thisform.Width
     Thisform.ImgBackGround.Height = Thisform.Height


Destroy Event

     WITH Thisform
       IF FILE(.cTempGradFile)
         CLEAR RESOURCES (.cTempGradFile)
         ERASE (.cTempGradFile)
      ENDIF
    ENDWITH


Las nuevas clases GDI+

El código que he presentado en el evento LOAD funciona muy bien; pero tiene una apariencia bastante fea, al compararlo con lo que seremos capaces de hacer cuando sean liberadas las nuevas clases Sedna-X GDI+

El código que aparece a continuación va a sustituir todo el código relacionado con la creación del color degradado en el evento LOAD.

¡Es que no puedo esperar a que estén finalizadas estas clases!

Su trabajo es realmente brillante, y va a añadir mucho más que una clase envoltorio (wrapper)

     * Crear una imagen con degradado lineal GDI+ utilizando
     * las clases xfc GDI+ de Bo Durban y Craig Boyd
     System = NEWOBJECT("xfcSystem","system.vcx")
     LOCAL loBmp AS xfcBitmap
     LOCAL loGfx AS xfcGraphics
     LOCAL loBrush AS xfcBrush
     WITH System.Drawing
       loBmp = .Bitmap.New(1, Thisform.Height)
       loGfx = .Graphics.FromImage(loBmp)
       loBrush = .Drawing2D.LinearGradientBrush.New( ;
         .Rectangle.New(0, 0, 1, Thisform.Height), ;
         .Color.FromRGB(lnRGBColor1), .Color.White, 1)
       loGfx.FillRectangle(loBrush, loBrush.Rectangle)
       loBmp.Save(lcGradFile, .Imaging.ImageFormat.Bmp)
     ENDWITH

 

Parte 2

Como explicó Malcolm Greene, (http://weblogs.foxite.com/vfpimaging/archive/2006/06/13/1825.aspx#comments) la misma técnica puede ser utilizada para contenedores VFP.

De acuerdo con MSDN, "La clase LinearGradientBrush define una brocha que pinta un color degradado en el que el color cambie uniformemente desde la línea de límite que comienza el degradado hasta la línea final del límite de la brocha. Las líneas de borde de un degradado lineal son dos líneas rectas paralelas. El degradado de color es perpendicular a las líneas de borde, cambiando gradualmente a través del movimiento desde la línea de borde inicial a la línea de borde final. El color degradado tiene un color en la línea de borde inicial y otro en la línea de borde final."

Los parámetros principales a pasar a LinearGradientBrush son:

  • point1 Punto inicial de degradado. La línea de borde inicial pasa a través del punto inicial.
  • point2 Punto final de degradado. La línea de borde final pasa a través del punto final.
  • color1 Color ARGB en la línea de borde inicial de esta brocha con degradado lineal.
  • color2 Color ARGB en la línea de borde final de esta brocha con degradado lineal.

En este caso, he creado una imagen de 1 pixel de ancho con la altura del formulario. Luego, creé una brocha LinearGradientBrush utilizando las coordenadas (0,0) como el punto 1, y coordenadas (0, ThisForm.Height) como el punto 2. El color1 tiene el ARGB de cualquier color seleccionado, y color2 como White(RGB(255,255,255)). Dentro de la imagen dibujé un rectángulo utilizando LinearGradientBrush y guardé en formato BMP. Un objeto Image de VFP es el responsable de "estirar" esta imagen de flecha para acomodarla con el ancho del formulario. Esta técnica permite guardar una imagen pequeña.


¡GDI brinda además degradados lineales horizontales, verticales y diagonales! Entonces, utilizando la misma técnica podemos crear fácilmente otros efectos.

Degradado horizontal

Para el degradado horizontal necesitamos pasar como Point1 y Point2 dos coordenadas con la misma "y". Es fundamental que los dos puntos tengan la misma coordenada (Y) para hacer que la línea conecte con ellos horizontalmente.


Degradado diagonal

Para el degradado diagonal, las dos coordenadas deben crear una línea diagonal, tales como punto (0,0) y punto (50,50). Esto creará una línea diagonal entre aquellos dos puntos, comenzando desde la esquina superior izquierda hasta la esquina inferior derecha del formulario, tal y como se muestra a continuación:


Si cambiamos las coordenadas (0,50) y (50,0), la línea diagonal va a finalizar en la esquina superior del formulario


Entonces, en nuestro caso, Solamente, hice el siguiente cambio sobre el código original de la entrada anterior:

     lnGradPixels = 100 && Ancho de la línea de degradado
     lnGradMode = 4 && Rangos desde 1 a 4
     DO CASE
       CASE lnGradMode = 1 && Vertical
         x1 = 0
         y1 = 0 
         x2 = 1
         y2 = lnGradPixels
       CASE lnGradMode = 2 && Horizontal
         x1 = 0
         y1 = 0
         x2 = lnGradPixels
         y2 = 1
       CASE lnGradMode = 3 && Diagonal SuperiorIzquierda -> InferiorDerecha
         x1 = 0
         y1 = 0
         x2 = lnGradPixels
         y2 = lnGradPixels
       CASE lnGradMode = 4 && Diagonal InferiorIzquierda -> SuperiorDerecha
         x1 = 0
         y1 = lnGradPixels
         x2 = lnGradPixels
         y2 = 0
     ENDCASE

     lnWidth = IIF(lnGradMode = 1, 1, lnGradPixels)
     lnHeight = IIF(lnGradMode = 2, 1, lnGradPixels)


La brocha LinearGradientBrush se creará utilizando las coordenadas (x1,y1) y (x2,y2). La imagen tendrá un tamaño lnWidth, lnHeight. La variable lnGradPixels significa el tamaño en píxeles de la imagen que se va a crear. En el envio anterior, utilicé "Thisform.Height". Después de algunas pruebas, he visto que empleando 60 píxeles creará un degradado de calidad que se expandirá por el objeto imagen hasta llenar todo el formulario.

Entonces, cree cualquier formulario y agregue el siguiente código en los eventos LOAD y DESTROY. Cambie los valores de la variable lnGradMode a cualquier valor entre 1 y 4, para ver el formulario con cuatro tipos de degradado. Cambie además lnGradPixels a 5,20 y 60. No olvide redimensionar el formulario.

Load Event

     LOCAL lcGradFile, lnGradMode, lnGradPixels, x1, y1, x2, y2, lnWidth, lnHeight
     lcGradFile = ADDBS(SYS(2023))+SYS(2015)+".bmp"
     This.AddProperty("cTempGradFile",lcGradFile)
     lnGradPixels = 60
     lnGradMode = 4
     DO CASE
       CASE lnGradMode = 1 && Vertical
         x1 = 0
         y1 = 0
         x2 = 1
         y2 = lnGradPixels
       CASE lnGradMode = 2 && Horizontal
         x1 = 0
         y1 = 0
         x2 = lnGradPixels
         y2 = 1
      CASE lnGradMode = 3 && Diagonal SuperiorIzquierda > InferiorDerecha
         x1 = 0
         y1 = 0
         x2 = lnGradPixels
         y2 = lnGradPixels
      CASE lnGradMode = 4 && Diagonal InferiorIzquierda > SuperiorDerecha
         x1 = 0
         y1 = lnGradPixels
         x2 = lnGradPixels
         y2 = 0
     ENDCASE

     lnWidth = IIF(lnGradMode = 1, 1, lnGradPixels)
     lnHeight = IIF(lnGradMode = 2, 1, lnGradPixels)
     IF FILE(lcGradFile)
       CLEAR RESOURCES (lcGradFile)
     ENDIF
     LOCAL lnRGBColor1
     lnRGBColor1 = RGB(0,128,255) && Azul

     * Crea una imagen degradada
     SET CLASSLIB TO HOME() + "ffc/_gdiplus.vcx" ADDITIVE

     * Crea un objeto Color y almacena en
     * variables los valores de color ARGB
     LOCAL loClr AS GpColor OF HOME() + "ffc/_gdiplus.vcx"
     LOCAL lnColor1, lnColor2
     loClr = CREATEOBJECT("gpColor")
     loClr.FoxRGB = lnRGBColor1
     lnColor1 = loClr.ARGB
     loClr.FoxRGB = RGB(255,255,255) && White
     lnColor2 = loClr.ARGB
   
     * Crea un bitmap
     LOCAL loBmp AS GpBitmap OF HOME() + "ffc/_gdiplus.vcx"
     loBmp = CREATEOBJECT("gpBitmap")
     loBmp.Create(lnWidth, lnHeight)

     * Obtiene un objeto gráfico bitmap
     LOCAL loGfx AS GpGraphics OF HOME() + "ffc/_gdiplus.vcx"
     loGfx = CREATEOBJECT("gpGraphics")
     loGfx.CreateFromImage(loBmp)

     * Declara API
     DECLARE Long GdipCreateLineBrushI IN GDIPLUS.DLL ;
       String point1, String point2, ;
       Long color1, Long color2, ;
       Long wrapMode, Long @lineGradient

     * Crea una brocha con degradado
     LOCAL loBrush AS GpBrush OF HOME() + "ffc/_gdiplus.vcx"
     LOCAL hBrush && Brush Handle
     hBrush = 0
     GdipCreateLineBrushI(BINTOC(x1,"4rs")+BINTOC(y1,"4rs"), ;
       BINTOC(x2,"4rs")+BINTOC(y2,"4rs"), ;
       lnColor1, lnColor2, 0, @hBrush)
     loBrush = CREATEOBJECT("gpBrush")
     loBrush.SetHandle(hBrush, .T.)

     * Llena el bitmap con nuestro degradado
     loGfx.FillRectangle(loBrush,0,0,lnWidth, lnHeight)
     loBmp.SaveToFile(lcGradFile,"image/bmp")
     Thisform.AddObject("ImgBackGround","Image")
     WITH Thisform.ImgBackGround
       .Stretch = 2 && Expandir
       .Width = Thisform.Width
       .Height = Thisform.Height
       .Anchor = 15 && Redimensiona Ancho y Alto
       .Picture = lcGradFile
       * .PictureVal = FILETOSTR(lcGradFile)
       * .PictureVal = LOADPICTURE(lcGradFile)
       * ERASE (lcGradFile)
       .ZOrder(1)
       .Visible = .T.
     ENDWITH
   RETURN


Destroy Event

     WITH Thisform
       IF FILE(.cTempGradFile)
         CLEAR RESOURCES (.cTempGradFile)
         ERASE (.cTempGradFile)
       ENDIF
     ENDWITH


Una ligera modificación fue agregar ZOrder(1), para asegurarse de que el objeto image agregado está al frente, y mantener al fondo de todos los objetos del formulario. ¡Gracias Aílsom !

Gracias a Malcolm Greene, el código para el evento Resize se eliminó y sustituyó por: .Anchor = 15 && Redimensiona de Ancho y de Alto. VFP9 trajo muchas novedades buenísimas, y debo admitir que hasta ahora apenas he probado algunas de ellas.

Malcom sugirió además enviar los binarios desde la imagen creada a la propiedad PictureVal del objeto imagen. No se por qué; pero en algunas PCs el dibujo aparece rotado en unos 90 grados. Además, en Windows NT, la parte blanca del degradado se sustituye por transparencia. Por tanto, de momento, mantengo el código en el evento Destroy para garantizar que la imagen creada se elimina del disco.

Estoy seguro de que existe una buena solución para esto ¿será que alguien me lo puede explicar?



Nuevas clases GDI+

Craig y Bo agregaron a la nueva biblioteca además de todas las funciones GDI+, otras clases que van a hacer, que el uso de GDI+ sea realmente sencillo y lo más importante, muy intuitivo. No habrá más necesidad de llamar directamente a las funciones API para GDI+, control de objetos. La creación de imágenes será realmente intuitiva.

Uno de los muchos agregados es la clase IMAGECANVAS. Es una subclase de la clase nativa Image que fue creada para recibir un dibujo. La ventaja de utilizar esta clase es que genera gráficos a gran velocidad (de acuerdo con Craig y Bo unas 30 veces más rápido que guardar una imagen a disco y cargar a un objeto image). No habrá acceso a disco, una vez que la imagen es manipulada directamente desde la memoria. El usuario tendrá solamente que colocar código para dibujar la imagen en el método "BeforeDraw" del objeto y es todo.

En el caso de fondos degradados en formularios, tendremos solamente que agregar el objeto "ImageCanvas" y en el método BeforeDraw de este objeto, poner el código. SÓLO 5 LINEAS!!! Gracias a Craig Boyd por enviarme este ejemplo.

BeforeDraw Event

     LOCAL loBrush AS xfcLinearGradientBrush
     WITH _Screen.System.Drawing
       loBrush = .Drawing2D.LinearGradientBrush.New(This.Rectangle, ;
         .Color.FromRGB(0,128,255), .Color.White, ;
         .Drawing2D.LineargradientMode.ForwardDiagonal)
       This.oGfx.FillRectangle(loBrush, This.Rectangle)
     ENDWITH

¿Cómo se siente empleando estas clases?

Existen otros muchos efectos para crear con LinearGradientBrushes. De forma predeterminada, el color en un degradado lineal cambia uniformemente. Sin embargo, es posible personalizar un gradiente lineal de tal forma que el color cambie de forma no uniforme, creando degradados que utilicen más de dos colores.

A partir de ahora, intentaré ir mostrando estas características utilizando la clase nueva. Debo confesar que no me siento muy listo al presentar este envio donde he sustituido 70 líneas por 5 !

En el archivo adjunto, estoy enviando dos formularios. El primero, Gradient.SCX crea un formulario sencillo, con código en los eventos LOAD y DESTROY. Intente también el formulario Gradient2.SCX, que permitirá personalizar al vuelo, los colores de degradado y la dirección.



Descarga

Código fuente de este formulario de ejemplo gradient.zip

Haga clic aquí para descargar el archivo gradientnew.zip

 

Vea también

Objetos con fondos de colores degradados con GDI+ Revisado - Comunidad de Visual FoxPro - Enlace externo

Más artículos similares - Comunidad de Visual FoxPro - Enlace externo

 

 

 


 

Referencias

Artículo original: Gradient Backgrounds in your forms with GDI Part 1 - Part 2 --> en CVF
http://weblogs.foxite.com/vfpimaging/archive/2006/06/13/1825.aspx 
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York 

 


 

 

 



error: Contenido protegido