We have already mentioned the first and major difference between the two versions: Whereas GDI+ exposes its functionality as both managed and unmanaged classes (through the System.Drawing namespace), GDI is unmanaged only. Beside this major difference, some of the important changes in GDI+ are as follows:
- No handles or device contexts
- Object-oriented approach
- Graphics object independence
- Methods overloading
- Separate methods for draw and fill
- Regions and their styles
Elimination of Handles and Device Contexts
As a GDI programmer, you must be familiar with the device context. A device context is a structure that stores information about a particular display device, such as a printer or monitor. This structure specifies how the graphics objects will be drawn on the output device. The device context also stores information about the properties of graphics objects, such as the quality of rendering and so on. To draw an object on a device, first an application needs to get a handle to the device context (HDC), which is used by GDI to send information to the device.
In GDI+, the concept of device context and handle to the device context is replaced by the Graphics object. The Graphics class provides methods and properties to draw various graphics objects; these methods and properties are very easy to use compared to the earlier device context-based programming model.
Suppose that you need to draw a line from point (20,20) to point (200,200). In GDI, first an application creates and HDC using the BeginPaint function, which takes a window handle and a PAINTSTRUCT structure. Alternatively, you can call the GetDC function. To draw a line the application must create a pen object and draw a line using this pen. An application can obtain a pen object by making a call to the CreatePen function, which returns a handle to the pen.
Before starting to draw, the application needs to call the SelectObject function, which takes the device context and pen handle as arguments. Now the application can draw any graphics object. The application calls the EndPaint function to end the drawing process. For example, the code snippet in Listing 1.1 draws a line using the MoveToEx and LineTo Functions.
LISTING : C++ code to draw a line
LRESULT APIENTRY MainWndProc (HWND hwnd, UINT message, WPARAM, wParam, LPARAM 1Param)
{
PAINTSTRUCT ps;
Switch (message)
{
case WM-PAINT:
HDC handle;
PAINTSTRUCT pstruct;
HPEN Pen;
handle=BeginPaint (hWnd, &pstruct);
hpen=CreatePen (PS_SOLID, 5,
RGB (255,255,0));
SelectObject (handle, hPen);
MoveToEx (handle,20,20,NULL);
LineTo (handle, 200,200);
EndPaint (hWnd, &pstruct);
}
}
Now let's see the same example in GDI+: First you need a Graphics object associated with a form, which is usually available on the form's Form_Paint event or OnPaint method. Once you've got the Graphics object associated with a form, you can call its draw and fill methods to draw and fill various graphics objects, such as lines, rectangles, and curves. For example, the code written in Listing 1.2 is the form's paint method. As this code shows, first we get a Graphics object associated with the form by using PaintEventArgs. Graphics. After that we create a Pen object and pass it as an argument to the DrawLine method. The DrawLine method takes a Pen object and the starting and ending points of a line, and draws a line on the form. Notice also in Listing 1.2 that there is no MoveTo call.
LISTING: GDI+ code in C# to draw a line
private void Form1_Paint (object sender, System.Windows.Forms.PaintEventArgs e)
{
Graphics g = e.Graphics;
Pen pn = new Pen (Color.Red, 3);
g.DrawLine(pn, 20,20,200,200);
}
Object-Oriented Approach
If you compare Listing 1.1 and 1.2, it's easy to see that the GDI+ model is more flexible, easier to use, and more object-oriented. GDI provides functions to draw graphics objects; GDI+ provides objects. Each graphics primitive is an object. For example, in GDI+, a pen is represented by a Pen object, as opposed to the HPEN structure in GDI.
Graphics Object Independence
In GDI, first you select a brush, path, image, or font and pass this object a device context. Then you use the device context handle to draw a graphics object, which means all the objects drawn using that device context will have the same effects.
Unlike GDI, GDI+ provides an object-independent model, which means that pens, brushes, images, or fonts can be created and used independently and can be changed at any time. In addition, an application can even use different pens to draw different graphics objects on the same form, which is not true in the case of a device context.
Method Overloading
GDI+ methods provide many overloaded forms to provide more flexibility to developers. For example, the DrawRectangle method has three overloaded forms:
public void DrawRectangle (Pen, Rectangle);
public void DrawRectangle (Pen, int, int, int, int);
public void DrawRectangle (Pen, float, float, float, float);
These forms allow developers to draw a rectangle from a rectangle object, four integer values, or floating point values. The DrawRectangle method draws a rectangle specified by a coordinate pair, a width, and a height. The DrawImage method, used to draw images, has no fewer than 30 overloaded forms.
Draw and Fill Methods
Drawing and filling are analogous to writing and painting. When you write, you use a pen to "draw" symbols made up of lines and curves. Painting means you take a brush, dip it into a color, and fill in areas with the color.
In GDI, both actions (fill and draw) are done in one step. For example, consider drawing and filling a rectangle. First an application creates a pen and a brush and calls SelectObject to select that pen and brush. Then the application calls the Rectangle method, which draws and fills the rectangle. Listing 1.3 shows a code snippet that draws and fills a rectangle.
LISTING: GDI code to draw and fill a rectangle
hBrush = CreateHatchBrush(HS_CROSS, RGB(255, 0, 0));
hPen = CreatePen(PS_SOLID, 3, RGB(255, 0, 0));
SelectObject(HDC, hBrush);
SelectObject(hdc, hpen);
Rectangle(hdc, 20, 20, 200, 200);
In GDI+, the Graphics class provides separate draw and fill methods. Fox example, the DrawRectangle method takes a Pen object and draws an outline of a rectangle, and the FillRectangle method takes a Brush object and fills the rectangle with the specified brush, as Listing 1.4 shows.
LISTING: GDI+ code to draw and fill a rectangle
Graphics g = e.Graphics;
Pen pn = new Pen(Color.Red, 3);
HatchBrush htchBrush = new HatchBrush(HatchStyle.Cross, Color.Red, Color.Blue);
g.DrawRectangle(pn, 50, 50, 100, 100);
g.FillRectangle(htchBrush, 20, 20, 200, 200);
Regions and Their Styles
Regions are another area where a GDI developer may find minor changes in GDI+. GDI+ provides several functions for creating elliptical, round and polygonal regions. As a GDI programmer, you are probably familiar with the CreatRectRgn, CreateEllipticRgn, CreateRoundRectRgn, CreatPolygonRgn, and CreatePolyPolygonRgn functions.
In GDI+, the Region class represents a region. The Region class constructor takes an argument of type GraphicsPath, which can have a polygon, a circle, or an ellipse to create a polygonal, round, or elliptical region, respectively.
Conclusion
Hope this article would have helped you in understanding GDI+ from a GDI Perspective. See my other articles on the website on GDI+ which are in continuation of this article.