IonicWind Software

IWBasic => Tutorials => Create a Custom Control => Topic started by: LarryMc on September 10, 2011, 03:41:53 PM

Title: 18. GDI+ Setup
Post by: LarryMc on September 10, 2011, 03:41:53 PM
As stated in the previous section, we can start drawing our control with the code structure already established. However, in the announcement of this tutorial effort we said we would be using the GDI+ library for our drawing.

Our main reason for opting for the GDI+ drawing functions is the lack of antialiasing with the standard GDI library.

A quick review.

When we normally draw a line at an angle it appears to be a stair step.  That is because pixels are rectangles.  If our infinitely thin line passes through a pixel the entire pixel is painted.  This technique of representing a line with a stair step is called aliasing; the stair step is an alias for the theoretical line.

GDI+ uses a drawing technique where the closer a pixel is to our theoretical line the more solid the color is.  The further a pixel is from the line the more transparent it is. This type of rendering is called antialiasing and results in a line that the human eye perceives as more smooth.  The attached image of two ellipses is an example from the OS SDK.

Antialiasing also helps the appearance of text that is rotated from the horizontal.

Since our gage control is round and the pointers rotate we will get the best appearance by using GDI+.

In order to use the GDI+ library functions we must first initialize GDI+.  We only need to do this once per application.  And, as usual, we will need to clean up when we are through.

We start by defining two global variables:

GdiplusStartupInput GDI_Start

The GdiplusStartupInput UDT structure is really of no concern to us except for one element which we will use to tell us whether or not we have already initialized GDI+.

The GDI_Token variable, which will have its value set when GDI+ is initialized, will be used during our cleanup.

We'll place the above two lines of code at the bottom of Section 2 in CCT_lib.iwb.

We then add the following code to the WM_CREATE portion of our message handler routine:

   IF (!GDI_Start.GdiplusVersion)
GDI_Start.GdiplusVersion = 1
IF GdiplusStartup(&GDI_Token, &GDI_Start, NULL)
   MESSAGEBOX 0,"Error initializing GDI+/nCan not proceed.","Fatal Error"
ONEXIT &ReleaseGdip, 0

When the first instance of our control is created in the user's application the IF statement will be TRUE.  The next line will insure that the IF statement will be FALSE when additional instances of our control are created.  This works because GDI_Start is a GLOBAL variable and not a local variable.

We then call the GdiplusStartup function. We pass it the addresses of our two global variables.  If the function fails for any reason we show an error message and close the application.

If the function is successful we use the IWBasic ONEXIT function to add our cleanup subroutine to the internal list of routines to execute when an application is shutdown.

The following is our cleanup subroutine:

SUB ReleaseGdip(pointer p),INT

Passing of a pointer parameter is a requirement of the ONEXIT function.  In this application we don't need to use it.  So here, all we are doing is calling the OS GdiplusShutdown function.  And we are passing it the value of our global GDI_Token variable.

The above subroutine will be placed at the bottom of Section 8 of CCT_lib.iwb. With that we have completed the required initialization and clean up of GDI+.

But we still can't use GDI+ drawing functions yet.

We spent the previous two sections discussing device contexts and how we draw to them.  It only makes sense that we some how tie GDI+ to the two DCs we've already created code for.

We will need to add the following line right before we start our block of code that does the drawing:

   GdipCreateFromHDC(hdc2, &pGraphics)
This will add a GDI+ graphics object to our DC.

And as always we will need to do our cleanup by adding the following line to both.

if (pGraphics) then GdipDeleteGraphics(pGraphics)

Of course, in both places we will need to declare that pGraphics is a POINTER.

At this point we have completed all our preparations so that we can start using our drawing functions.


Coming Next - Drawing the Background