2006-07-11

GRADIENT COMMAND BUTTONS WITH GDI+

This is a deprecated post. Please search in this blog for the next posts, for the improved gradient objects and background classes.

 

Using some of the techniques presented in my previous posts, (read gradient backgrounds in your forms with gdi+), I've created a very simple subclass of the commandbutton object, in order to create gradient background effects.

Please take note that this is an unfinished class, not to be used in production. I'm posting it here at this moment to show to people that we can obtain very cool effects using gdi+.

This is how the form looks in development mode:

1000.107.1970.GradDev

 

Below you can see the form running, when gdi+ creates the backgrounds.

1000.107.1971.GradRun

 

properties that you need to fill to have the desired results:

caption, fontbold, fontunderline, fontitalic, fontstrikethru

picture,

backcolor (with the main color to be used as background)

gradientmode (0 = no gradient 1 = vertical-default 2 = horizontal 3 = diagonal1 4 = diagonal2)

 

how the class was created:

I used the commandbutton base class, to make it have the most common usage and understanding possible, making the development mode the most seemed to the result obtained when running the form.

In the init event of the class, it verifies the gradient direction, and creates a lineargradient brush, using the color defined in the backcolor property of the object. The second color was set to white as default. Then it draws a rectangle using this brush in a picture just created, that has the same dimensions of the commandbutton.

The next step is to check if there is a picture assigned to the button; if yes, draw it to the left side, centered in the vertical.

If the caption property was set, then draw the string, centered in horizontal and vertical.

In this example i'm only using gifs with transparent background, so that the background is preserved..

 

the codes

The main code stays in the init event of the commandbutton subclass:

with this

local lcgradfile, lngradmode, lngradpixels, x1, y1, x2, y2, lnwidth, lnheight
lngradmode = .gradientmode
if lngradmode = 0
return && no gradient background !
endif

lcgradfile = addbs(sys(2023))+sys(2015)+".bmp"
.ctempgradfile = lcgradfile

local lcpicture, lccaption, lnrgbcolor1
lcpicture = .picture
lccaption = .caption
lnrgbcolor1 = .backcolor

lnwidth = .width
lnheight = .height

do case
case
lngradmode = 1 && vertical
y1 = 0
x2 = 1
y2 = lnheight
case lngradmode = 2 && horizontal
y1 = 0
x2 = lnwidth
y2 = 1
case lngradmode = 3 && diagonal topleft -> bottomright
y1 = 0
x2 = lnwidth
y2 = lnheight
case lngradmode = 4 && diagonal bottomleft -> topright
y1 = lnheight
x2 = lnwidth
y2 = 0
endcase

* create gradient image
set classlib to home() + "ffc/_gdiplus.vcx" additive

* create a colorobject and store argb color values to 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

* create a bitmap
local lobmp as gpbitmap of home() + "ffc/_gdiplus.vcx"
lobmp = createobject("gpbitmap")
lobmp.create(.width, .height)

* get a bitmab graphics object
local logfx as gpgraphics of home() + "ffc/_gdiplus.vcx"
logfx = createobject("gpgraphics")
logfx.createfromimage(lobmp)

* declare api
declare long gdipcreatelinebrushi in gdiplus.dll ;
string point1, string point2, ;
long color1, long color2, ;
long wrapmode, long @linegradient

* get a gradient brush
local lobrush as gpbrush of home() + "ffc/_gdiplus.vcx"
local hbrush && brush handle
hbrush = 0
gdipcreatelinebrushi(bintoc(0,"4rs") + bintoc(y1,"4rs"), ;
bintoc(x2,"4rs") + bintoc(y2,"4rs"), ;
lncolor1, lncolor2, 0, @hbrush)

lobrush = createobject("gpbrush")
lobrush.sethandle(hbrush, .t.)

* fill the bitmap with our gradient
logfx.fillrectangle(lobrush,0,0,.width, .height)

* draw the desired picture
if not empty(lcpicture)
local lopict as gpimage of home() + "ffc/_gdiplus.vcx"
lopict = createobject("gpimage")
lopict.createfromfile(lcpicture)

x1 = 1
y1 = (.height - lopict.imageheight) / 2
logfx.drawimageat(lopict,x1, y1)
endif

* draw the caption
#define fontstyleregular 0
#define fontstylebold 1
#define fontstyleitalic 2
#define fontstyleunderline 4
#define fontstylestrikeout 8

#define unitworld 0
#define unitdisplay 1
#define unitpixel 2
#define unitpoint 3
#define unitinch 4
#define unitdocument 5
#define unitmillimeter 6

if not empty(.caption)
local lnfontstyle
lnfontstyle = fontstyleregular + ;
iif(.fontbold, fontstylebold, 0) +;
iif(.fontitalic, fontstyleitalic, 0) +;
iif(.fontunderline, fontstyleunderline, 0) +;
iif(.fontstrikethru, fontstylestrikeout, 0)

local lofont as gpfont of home() + "ffc/_gdiplus.vcx"
lofont = newobject('gpfont', home() + 'ffc/_gdiplus.vcx')
lofont.create( .fontname ; && font name
, .fontsize ; && size in units below
, lnfontstyle ; && fontstyle
, unitpoint ) && units

* create solidbrush with the forecolor
local losolidbrush as gpsolidbrush of home() + "ffc/_gdiplus.vcx"
losolidbrush = newobject('gpsolidbrush', home() + 'ffc/_gdiplus.vcx','',0)

loclr.foxrgb = .forecolor
losolidbrush.brushcolor = loclr

* measure the height of the caption to calculate vertical position
local lostringsize as gpsize of home() + 'ffc/_gdiplus.vcx'
lostringsize = logfx.measurestringa(.caption, lofont)

lnpictwidth = iif(empty(lcpicture), 0,lopict.imagewidth)
x1 = lnpictwidth + ((.width - lnpictwidth - 1) - lostringsize.w) / 2
y1 = (.height - lostringsize.h) / 2

* create pointf with the position of caption
lctextpoint = bintoc(x1,'f') + bintoc(y1,'f')
logfx.drawstringa(.caption, lofont, lctextpoint, , losolidbrush)
endif

* save image to file
lobmp.savetofile(lcgradfile,"image/bmp")

.picture = lcgradfile

endwith
return

 

In destroy event, we just delete the temporary image created

if this.gradientmode = 0
return && no gradient background !
endif

with this
if file
(.ctempgradfile)
clear resources (.ctempgradfile)
erase (.ctempgradfile)
endif
endwith

 

to be improved:

- pictureposition - at this moment, it will always work as "1 - left of caption, centered relative to caption". vfp9 brings 14 position options, this can be done easily in a future version.

- add another property to receive the 2nd color ( at this moment, white - rgb(255,255,255) is default)

- permit to create 3 color gradients, allowing for example: blue - white - blue

- to deal with a disabled commandbuttons. please send suggestions / or pictures showing how the control should look when disabled !

- permit to receive any image, and create the transparency of the backgrounds.

 

The icons that i used to create this example were taken from http://www.iconbazaar.com , where you can find many cool gifs

 

07/19/2006 - updated version of the class

I've received many suggestions, and created a new version of the class, adding many other features.

You can download the most recent version of the class and some forms using it from this link :
http://weblogs.foxite.com/files/vfpimaging/gradobjects/gradobjects.zip

When running the form "testgradbuttons", please pass the mouse over the buttons and also click the "disable" button.

33 comments:

  1. Beautifull !!! Great visual class is amazing and easy utility.Thank you for it. And you keeping gating better.

    ReplyDelete
  2. Grande Cesar!

    O Mr. GDI


    Muito bom exemplo,

    Parabéns

    ReplyDelete
  3. Show de bola !


    Vou pegar o código para ver se aprendo um pouco :-)


    Abração

    ReplyDelete
  4. UPDATED VERSION OF THE CLASS
    I've received many suggestions, and created a new version of the class, adding many other features.

    I'd be grateful to receive comments, critics or suggestions, in order to improve the control.

    If anyone is interested, pls download the most recent version of the class and some Forms using it from this link :
    http://www.geocities.com/macmarbr/gradcmdbutton.zip

    When running the form "testGradButtons", please pass the mouse over the buttons and also click the "DISABLE" button.

    TIA

    Cesar

    ReplyDelete
  5. Looks very nice on these pictures!

    ReplyDelete
  6. Great class Cesar, thanks for sharing it. When you go with keyboard to a button it applies the nice efect (like when mouse is over it) but when you pass the mouse over another button even if you dont change focus, the button with the focus loses the effect.

    ReplyDelete
  7. Parabéns César!

    Belo trabalho!!!

    ReplyDelete
  8. Gracias Luis !

    I've already updated the class, fixing that bug, and some few enhancements.

    Thanks for testing !

    http://www.geocities.com/macmarbr/gradcmdbutton6.zip

    Cesar

    ReplyDelete
  9. Hi Cesar,


    Fantastic class, enabled me to do gradient backgrounds for any object that has a picture property.  I have also altered your code somewhat to enable printing of the hotkey character in a different color.  Parses out the \< and calculates the position to draw the character at, pretty simple really.  Not sure how to get the changes back to you.

    Cheers

    ReplyDelete
  10. Hi Keith,

    Great Idea !

    And easy to implement indeed.

    You can send your modifications to : cchalom at hotmail dot com

    Thanks for testing and evaluating the class.

    Cesar

    ReplyDelete
  11. Great that you fix the error. Hey Cesar, why don't you put this in VFPX to create a toolbox of components with gradient effects, we can have containers, Pageframes, etc. With the help of all and you we can create great stuff.

    ReplyDelete
  12. Maybe the best would be to send to VFP-X a project "MAKE IT COOL", in which people could work with all kinds of gradients, in all kinds of controls and menus. Recently, I've seen many solutions and ideas. You can visit Bernard Bout's blog entries here at Foxite too.
    I also don't know if this project would fill the VFP-X prerequisites.
    Maybe we can work together, adding features, using this space, UT forums, wherever. My intention is to share it with the community.
    If you want to help, you can contact me directly.
    Regards
    Cesar

    ReplyDelete
  13. Sure, can you be the leader? maybe we can make a schedule to define the steps to follow.

    ReplyDelete
  14. Yes, we can work together on that.

    Keith Gordijn sent me some cool modifications about to "enable printing of the hotkey character in a different color.  Parses out the \< and calculates the position"

    Thanks Keith, I hope to add this feature in the next version.


    Perhaps we can work together on that, also calling Bernard Bout, that has great ideas too, looking for the best performance.

    Pls contact me at cchalom at hotmail dot com

    ReplyDelete
  15. Estaba recibiendo el error que una función no estaba definida; registré la DLL y ese error ya no aparece, pero me aparece otro con respecto a una de las funciones BIN (creo que es la BINTOC); en la ayuda encontré que el segundo parámetro debe ser numérico, y en el código de la clase aparecen letras mayúsculas entre comillas.  Qué debo hacer?

    Gracias.


    I was receiving some error about "function not defined"; I reegistered the DLL and that error disapeared. But now I'm getting another respect to one of the BIN functions (BINTOC?, not sure this moment); on the help I found that the second parameter must be numeric, but on the class code ther are capital letters inside double comillas (I beg your pardon about my english).  What must I do?

    Thanks.

    ReplyDelete
  16. Hernan,
    Pls tell me exactly in which method and line the error is occurring. What VFP version are you using? The control works only with VFP9. VFP9 added some new and very important modifications in BINTOC and CTOBIN commands, that permit working with floats.

    Desculpe mi portuñol,
    Por favor, explique en que metodo el error esta ocorriendo.
    Que version de VFP estas utilizando ?
    El control funciona solamente con VFP9

    ReplyDelete
  17. I've published a new version of the class, with some new screenshots and a more detailed explanation about the features and properties to be set:
    http://weblogs.foxite.com/cesarchalom/archive/2006/07/26/2076.aspx

    ReplyDelete
  18. Sorry to post this here but i didn't finf how to contact cesar chalom

    I have been trying to use the two classes together (gradbuttons + imgcanvas) and i get a bug saying, too many nested loop and

    Fatal error: Exception code=C0000005 @ 12/13/05 08:17:56 AM. Error log file: C:\Program Files\Microsoft Visual FoxPro 9\vfp9err.log

    Called from -  masterconvert.destroy line 656  {C:\Program Files\Microsoft Visual FoxPro 9\convert.prg c:\program files\microsoft visual foxpro 9\convert.app}

    Called from -  convert line 143  {C:\Program Files\Microsoft Visual FoxPro 9\convert.prg c:\program files\microsoft visual foxpro 9\convert.app}



    Fatal error: Exception code=C0000005 @ 05/11/2006 16:39:15. Error log file: C:\Program Files\Microsoft Visual FoxPro 9\vfp9err.log

    Called from -  form1.gradobjects1.draw line 278  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}

    Called from -  form1.gradobjects1.init line 117  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}



    Fatal error: Exception code=C0000005 @ 05/11/2006 16:40:56. Error log file: C:\Program Files\Microsoft Visual FoxPro 9\vfp9err.log

    Called from -  form1.gradobjects1.draw line 278  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}

    Called from -  form1.gradobjects1.init line 117  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}



    Fatal error: Exception code=C0000005 @ 05/11/2006 16:41:32. Error log file: C:\Program Files\Microsoft Visual FoxPro 9\vfp9err.log

    Called from -  form1.gradobjects1.draw line 278  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}

    Called from -  form1.gradobjects1.init line 117  {c:\pressing\gradbuttons.vct c:\pressing\gradbuttons.vct}



    Fatal error: Exception code=C0000005 @ 17/11/2006 19:09:09. Error log file: C:\Program Files\Microsoft Visual FoxPro 9\vfp9err.log

    Called from -  gesterr line 351  {c:\pressing\depart.prg c:\pressing\depart.fxp}

    Called from -  ON...  line 0  { }

    Called from -  xfcgraphics.fillrectangle line 35  {c:\pressing\drawing.vct c:\pressing\drawing.vct}

    Called from -  form1.imgcanvas1.beforedraw line 21  {c:\pressing\menufichiers.sct c:\pressing\menufichiers.sct}

    Called from -  form1.imgcanvas1.draw line 4  {c:\pressing\gdiplusx.vct c:\pressing\gdiplusx.vct}

    Called from -  depart line 273  {c:\pressing\depart.prg c:\pressing\depart.fxp}

    ReplyDelete
  19. Hi Jean Pierre,

    This was a bug that happened if both the class was used together with _gdiplus.vcx (FFC class). This was already fixed, please download the class again, and tell me if it's working as desired. Thanks very much for reporting !

    ReplyDelete
  20. OMG, I feel in heaven ... these are just great

    Cesar you're great man ... and FoxPro just ROOOOCKS

    ReplyDelete
  21. Hola Cesar. Excellent work.

    Based on the above class (not the newer), I tried to do a "Gradient Label" class. I simply created a class based on Label and added the Init and Destroy methods above, removing the references to picture (although I want to add them back later, so I could have a Label that Depicts some text on a gradient background WITH an image), and adding the couple properties needed (gradientmode an cgradfile).

    The problem is, nothing happens. I mean, the label is rendered without the gradient and with no repositioning of the Caption.

    The .BMP is being generated OK, as I can see it in the TEMP directory, but it never gets rendered...

    Any hints ?
    Hola Furio,
    I'm really not sure that I fully understood your question...
    The gradient effect needs an image object. As Labels don't have a picture property, you can't directly change that. A workaround would be for you to set the original label's Visible to False, and ADDOBJECT an image, and point the picture property to the picture that you generated.
    Hope this helps
    Cesar

    ReplyDelete
  22. Andy of New ZealandMarch 30, 2007 at 1:38 AM

    Cesar you are indeed a top man. Your product is great.
    Most of my buttons are in either containers or command groups so I have expanded the gradobjects.formafterinit method to include those.
    Thanks for making my old tired app look brand new !
    Hi,
    I'm glad to know that it helps you. Just make sure to be using the latest release, because I'm always updating these classes. Can you better explain what you did in your case ?
    Regards
    Cesar

    ReplyDelete
  23. Versión en Español de este artículo en / Spanish version at http://www.portalfox.com/article.php?sid=2257

    ReplyDelete
  24. when i try to put the command button gradbuttons in my form, a screenn error display

    "Property value is out of bound"

    Thanks.

    Sorry for my inglish
    Hola Diego,
    Para ayudarle, necesito de mas informaciones, puedes enviarme un informe que muestra el error ?
    Gracias
    Cesar

    ReplyDelete
  25. it doesn'n accept wordwrap caption.

    thanks in advance

    Rivo

    ReplyDelete
  26. When I use wordwrap with the command button it become .F. when running

    ReplyDelete
  27. hi

    i want to copy jpg files form my thailand server to india's server by vf6,9 coding
    can u tell it can posible for me
    Hi,
    Sorry, but your question is out of the scope of this blog post. If you are looking for VFP support, you should visit the Foxcite forums: www.foxite.com/forum
    Registration is totally free and there you'll be able to interact with brilliant and helpful developers.

    ReplyDelete
  28. que bonita classe la verdad ya la probe y funciono de maravilla, lastima la nueva version que ya no existe para verla.

    ReplyDelete
  29. ya no puedes subir nuevamente la nueva versión?

    ReplyDelete
  30. Wow me  gusta mucho la programacion, pero apenas bengo empesando a estudiar y cada vez me gusta mas y mas .....espero que sigan dedicando tiempo a estas paginas web porque son buenisimas.....Felicidades,,,.....

    ReplyDelete