• Welcome to Theos PowerBasic Museum 2017.

News:

Attachments are only available to registered users.
Please register using your full, real name.

Main Menu

Working GDI+ code review

Started by Dan Gin zel, January 14, 2010, 01:52:21 AM

Previous topic - Next topic

0 Members and 1 Guest are viewing this topic.

Dan Gin zel

Greetings.

With my gratitude to this site, I was able to put together some GDI+ graphics.



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




[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

José Roca

 
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.


Dan Gin zel

Whoops on the DeleteObject. I had originally written that in GDI but the white curve looked terrible without smoothing.
[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

Patrice Terrier

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)


...

Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Dan Gin zel

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
[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

Patrice Terrier

#5
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.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Patrice Terrier

Dan,

Have a look on this, it is done with GDI only.

...
Patrice Terrier
GDImage (advanced graphic addon)
http://www.zapsolution.com

Dan Gin zel

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


[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]

Dan Gin zel

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!
[SIZE="1"]www.thecomputerarchive.com  Preserving the history of companies that advanced the computer revolution[/SIZE]