13 de octubre de 2006

Formularios con fondos degradados con GDI+ Parte 2

Artículo original: Gradient Backgrounds in your forms with GDI+ Part 2
http://weblogs.foxite.com/vfpimaging/archive/2006/06/22/1906.aspx
Autor: Cesar Ch.
Traducido por: Ana María Bisbé York


En mi entrada anterior con el mismo título, mostré cómo crear fondos con degradado VERTICAL en formularios. (Nota de la traductora: El autor se refiere a "Gradient Backgrounds in your forms with GDI+" que está traducido al español bajo el título "Formularios con fondos de colores degradados con GDI+")

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.

Haga clic aquí para descargar el archivo

No hay comentarios. :

Publicar un comentario