Greetings.
With my gratitude to this site, I was able to put together some GDI+ graphics.
(http://www.bullthumper.com/images/tab3.png)
My goal is to draw certain objects dynamically rather than having to use images from the resource file.
Below is a snippet of the source that generated the image. Basically, I am presently passing the width and height of the button along with a radius value for the corner curves.
I have these questions:
1. Can anyone see any resource leaks?
2. Is this good/bad/ugly GDI+ from a technique perspective?
3. The sample attempts to simulate the glossy button look. Are there better techniques that can be done using GDI+ ?
4. Does anyone have any tips on how to get the hang of bezier curves?
5. Is it permissible or recommended to execute GDIPlusStartup / GDIPlusShutdown on a per routine basis or once for the entire application?
Anyhow, thanks in advance for your responses in hopes that I'll implement GDI+ well without making common mistakes that will affect me down the road.
Thanks
Dan
StartupInput.GDIPlusVersion = 1
IF GDIplusStartup(GDItoken, StartupInput, BYVAL %NULL) = 0 THEN
Picture = EZ_CreatePicture(w, h)
hDC = EZ_StartPictureDraw(Picture)
Result = GDIPCreateFromHDC(hDC, hGraphics)
' Draw the background
color1 = GDIPlusMakeARGBColor(255, 110, 110, 110)
GDIPCreatePen1(color1, 0, %UnitWorld, hPen)
GDIPCreateSolidFill color1, hBrush
GDIPFillRectangle hGraphics, hBrush, 0, 0, w, h
GDIPDeleteBrush hBrush
GDIPDeletePen hPen
' Create the clipping region
GDIPCreatePath %FillModeAlternate, hPath
GDIPAddPathLine hPath, 2, h, 2, 2 + r
GDIPAddPathBezier hPath, 2, 2 + r, 2, 2 + (r / 3), (r / 3), 2, r, 2
GDIPAddPathLine hPath, r, 2, w - r - 3, 2
GDIPAddPathBezier hPath, w - r - 3, 2, w - 3 - (r / 3), 2, w - 3, (r / 3), w - 3, r
GDIPAddPathLine hPath, w - 3, r, w - 3, h
GDIPClosePathFigure hPath
GDIPCreateRegionPath hPath, hRegion
hStatus = GdipSetClipRegion(hGraphics, hRegion, %CombineModeReplace)
' Draw the gradients
rc.x = 0
rc.y = 0
rc.nWidth = w
rc.nHeight = h * 0.26
color1 = GdiPlusMakeARGBColor(255, 255, 255, 255)
color2 = GdiPlusMakeARGBColor(255, 0, 68, 135)
hStatus = GdipCreateLineBrushFromRect(rc, color1, color2, %LinearGradientModeVertical, %WrapModeTile, hBrush)
hStatus = GdipFillRectangle(hGraphics, hBrush, rc.x, rc.y, rc.nWidth, rc.nHeight)
DeleteObject hBrush
rc.x = 0
rc.y = h * 0.24
rc.nWidth = w
rc.nHeight = h * 0.75
color1 = GdiPlusMakeARGBColor(255, 0, 68, 135)
color2 = GdiPlusMakeARGBColor(255, 255, 254, 217)
hStatus = GdipCreateLineBrushFromRect(rc, color1, color2, %LinearGradientModeVertical, %WrapModeTile, hBrush)
hStatus = GdipFillRectangle(hGraphics, hBrush, rc.x, rc.y, rc.nWidth, rc.nHeight)
GDIPDeleteBrush hBrush
' Remove the clipping region
GDIPSetInfinite hRegion
hStatus = GdipSetClipRegion(hGraphics, hRegion, %CombineModeReplace)
' Now draw the white transparent border
GDIPSetSmoothingMode hGraphics, %SmoothingModeHighQuality
GDIPCreatePath %FillModeAlternate, hPathOutline
GDIPAddPathLine hPathOutline, 5, h, 5, 5 + r
GDIPAddPathBezier hPathOutline, 5, 5 + r, 5, 5 + (r / 3), (r / 3) + 3, 5, r + 3, 5
GDIPAddPathLine hPathOutline, r + 3, 5, w - r - 6, 5
GDIPAddPathBezier hPathOutline, w - r - 6, 5, w - 6 - (r / 3), 5, w - 6, (r / 3) + 3, w - 6, r + 3
GDIPAddPathLine hPathOutline, w - 6, r + 3, w - 6, h
color1 = GDIPlusMakeARGBColor(63, 255, 255, 255)
GDIPCreatePen1(color1, 4, %UnitWorld, hPen)
GDIPDrawPath hGraphics, hPen, hPathOutline
GDIPDeletePen hPen
GDIPDeletePath hPathOutline
GDIPDeletePath hPath
' Now draw the black border line
GDIPCreatePath %FillModeAlternate, hPathOutline
GDIPAddPathLine hPathOutline, 2, h, 2, 2 + r
GDIPAddPathBezier hPathOutline, 2, 2 + r, 2, 2 + (r / 3), (r / 3), 2, r, 2
GDIPAddPathLine hPathOutline, r, 2, w - r - 3, 2
GDIPAddPathBezier hPathOutline, w - r - 3, 2, w - 3 - (r / 3), 2, w - 3, (r / 3), w - 3, r
GDIPAddPathLine hPathOutline, w - 3, r, w - 3, h
color1 = GDIPlusMakeARGBColor(255, 0, 0, 0)
GDIPCreatePen1(color1, 2, %UnitWorld, hPen)
GDIPDrawPath hGraphics, hPen, hPathOutline
GDIPDeletePen hPen
GDIPDeletePath hPathOutline
GDIPDeletePath hPath
' Done
DeleteObject hGraphics
EZ_EndPictureDraw
EZ_GetCanvasSize FormName$, CID&, i, j
EZ_StartDraw FormName$, CID&, i, j, ""
EZ_CDrawPicture 0, 0, w, h, Picture, ""
EZ_EndDraw
EZ_FreeImage Picture
GDIPlusShutdown GDItoken
End If
I see a DeleteObject hBrush that should be GdipDeleteBrush hBrush and a DeleteObject hGraphics that should be GdipDeleteGraphics pGraphics.
I use GDIPlusStartup when the application starts and GDIPlusShutdown wehn it ends. I don't see the need or convenience to do it more than once.
Whoops on the DeleteObject. I had originally written that in GDI but the white curve looked terrible without smoothing.
You must be aware that GDI+ is not hardware accelerated, and the code you are using could slowdown the redrawing of your EZGUI window if you are doing this during each %WM_PAINT message.
I confirm that GDIPlusStartup and GDIPlusShutdown, must be used only once per session.
Using transparent images from resource would be much faster, resizing just the part that have changed.
For BEZIER curve, here is a quick cut and paste from the code that was provided with my old GDIplus Helper toolkit.
CASE %ID_DRAWBEZIERCURVE ' Draw Bezier Curve
hDC& = skGetHdcMemBmp(skCTL&)
' Initialize the graphics class
CALL GdipCreateFromHDC(hDC&, graphics&)
' Create a pen to draw with
CALL GdipCreatePen1(%ColorsMediumAquamarine, 2, %UnitPixel, pen&)
' Add some anti-alias!
CALL GdipSetSmoothingMode(graphics&, %SmoothingModeAntiAlias)
' Draw the bezier line
CALL GdipDrawBezierI(graphics&, pen&, 10, 100, 100, 10, 150, 150, 200, 100)
' Cleanup
CALL GdipDeletePen(pen&)
CALL GdipDeleteGraphics(graphics&)
' Display result
CALL skUpdateWindow(skCTL&, %FALSE)
...
Thank you José and Patrice for your replies.
Patrice, by "session", that sounds like for the entire program, to Startup once and Shutdown once on application close. Am I understanding that correctly?
In the past, I have used transparent images from the resource file, but they didn't involve gradients. In this case, I would have to keep the height of the tab control consistent. However the goal for the next version of TDesk is to make everything scalable so that it fits the screen, including scaling the fonts. The reason is that I have people wanting to run the program full screen on ~50" TVs at 1920x1080 resolution and they want to be able to read everything across the room.
Therefore the intention is to draw the buttons and controls when the screen is resized and store them in sprites. They can be moved easily to give an animation effect and changed by selecting a different frame. From the operation standpoint, I think it will perform very nicely, but I do share your concern about the time to generate the elements, especially during a resize event.
Finally, on the beziers, I did use them in my tab to make the curve, but it's not a perfect symmetrical curve. I am still trying to get the hang of using the two control points to get the curve I want. I've been trying to find resources, such as Wikipedia and such that explain what these control points really mean and how they affect the shape of the curve, but so far, all I have found are the formulas, but I shall keep searching and more trial and error.
Thank you again for your insights.
Dan
QuoteAm I understanding that correctly?
YES
You should give a look at the articles i wrote in my "SDK programming" section, especially the thread entitled "take control of your buttons".
The "Button" class is one of the most versatile Windows class to create your own SUPERCLASS.
...
Dan,
Have a look on this (http://www.leandroascierto.com.ar/tips.php), it is done with GDI only.
...
Very good examples. I'm sure I'll learn a trick or two! Thank you very much for the link.
My next step is to create glows. Any suggestions there?
I've been thinking about drawing a thick mostly transparent line (like 2 to 5%) to start with and then right over the top to draw another thinner line and repeat until I reach a line thickness of 1.
Dan
Patrice, the example with the image has a background clearly illustrate why transparency in the fills and lines are the key. He also shifted (or enlarged) the background to give a better through-the-lens effect. These are some of the reasons your graphics have such an impressive feel to them. Now if I could ever write a program that doesn't need 1,000s of controls (slight exaggeration) where that would look good!