Issue dated - 06th January 2003

-


CURRENT ISSUE
INDIA NEWS
INDIA TRENDS
STOCK FILE
OPINION
NEWS ANALYSIS
E-BUSINESS
COMPANY WATCH
PERSONAL TECH.
TECHNOLOGY
TECHSPACE
INDIA COMPUTES
BOOK REVIEWS
PRODUCTS
EVENTS
COLUMNS
TECH FORUM

THE C# COLUMN

BETWEEN THE BYTES
TECHNOLOGY
SPECIALS <NEW>
HMA BANKBIZ
EC SERVICES
ARCHIVES/SEARCH
IT APPOINTMENTS
WRITE TO US
SUBSCRIBE/RENEW
CUSTOMER SERVICE
ADVERTISE
ABOUT US

 Network Sites
  IT People
  Network Magazine
  Business Traveller
  Exp. Hotelier & Caterer
  Exp. Travel & Tourism
  Exp. Backwaters
  Exp. Pharma Pulse
  Exp. Healthcare Mgmt.
  Express Textile
 Group Sites
  ExpressIndia
  Indian Express
  Financial Express

 
Front Page > TechSpace > Story Print this Page|  Email this page

GDI+ — An extension to GDI

The C# Column - Yashavant Kanetkar

If you have programmed under Windows, you would definitely be familiar with the term GDI (Graphical Device Interface). GDI simplifies drawing by providing an interface to the hardware devices like the screen or printer, such that the programmers don’t need to bother about hardware details and their differences. The same program can work on different display adapters, printers, keyboards, etc without any modifications to the code.

.NET uses GDI+, an extension to GDI, which further simplifies drawing. GDI+ has added several new features like graphics paths, support to image file formats, image transformation, etc. GDI+ has also introduced fundamental changes in the programming model used by GDI.

Changes in programming model
GDI uses the concept of Device Context (DC). Device Context is a structure that stores all the drawing related information, namely, features of the display device and attributes that decide the appearance of the drawing. Every device context is associated with a window. To draw on a window, one must first obtain a device context of that window. To change any attribute, say, pen colour, it first has to be selected in the device context by calling the SelectObject( ) method. Once selected, all the drawing is done using this pen, until such time as another pen is selected in device context.

GDI+ works with ‘graphics context’ that plays a similar role as device context. The graphics context is also associated with a particular window and contains information specifying how a drawing would be displayed. However, unlike device context, it does not contain information about pen, brush, font, etc. In order to draw with a new pen we simply have to pass an object of Pen class to the DrawLine( ) method (this method draws a line on window). We can pass different Pen objects in each call to DrawLine( ) method to draw the lines in different colours. Thus GDI uses a stateful model, whereas GDI+ uses a stateless model. The Graphics class encapsulates the graphics context. Not surprisingly, most of the drawing is done by calling methods of the Graphics class.

Working with GDI+
So let’s learn how to draw text and graphics using GDI+ by writing a small program. Create a Windows Application. Windows programmers know that a window receives WM_PAINT message when it is to be painted. We need to handle this message if we want to do any painting in the window. In .NET we can do this either by overriding the virtual method OnPaint( ) of the Form class or by writing a handler for the Paint event. The base class implementation of OnPaint( ) invokes the Paint event handler through delegate. Hence we should write our code in the Paint event handler.

Add the Paint handler to the form. The Form1_Paint( ) handler would look like this.

private void Form1_Paint (object sender, PaintEventArgs e)
{
}

The first parameter passed to the Form1_Paint( ) handler contains the reference to the object of a control that sends the event. The second parameter contains more information about the Paint event. We would first see how to display a string on the form. To display the string we would use DrawString( ) method of the Graphics class.

private void Form1_Paint    ( object sender, PaintEventArgs e )
{
	Graphics g = e.Graphics;
	Font myfont = new Font (“Times New Roman”, 60);
StringFormat f = new StringFormat(); f.Alignment = StringAlignment.Center; f.LineAlignment = StringAlignment.Center; g.DrawString (“Hello!”,myfont,Brushes.Blue,ClientRectangle,f); }

The Graphics property of the PaintEventArgs class contains reference to the Graphics object. We can use this reference for drawing. In a handler other than Paint event handler we can obtain the Graphics reference using the CreateGraphics( ) method of the Form class. The DrawString() method has several overloaded versions. We used one that allows us to display centrally aligned text in desired font and colour. The first parameter passed to the DrawString( ) method is the string we wish to display. The second parameter is the font in which text would get displayed. We have created a font by passing the font name and font size to the constructor of the Font class. The text gets filled with the brush colour specified as the third parameter. The fourth parameter specifies the surrounding rectangle. We have passed ClientRectangle property of Form class that contains a rectangle representing the client area of the form. To centrally align the text we have used the StringFormat class. The Alignment and LineAlignment properties of this class contain horizontal and vertical alignment of text respectively.

The Graphics class contains various methods to draw different shapes. This includes drawing rectangle, line, arc, bezier, curve, pie, etc. We would add the code in Form1_Paint( ) handler that draws rectangles in different pens and brushes. You would be able to draw other shapes on similar lines.

The following code draws a rectangle using green coloured pen having line thickness of 3.

Pen p=new Pen(Color.Green, 3);
g.DrawRectangle(p,20,20,150,100);

The Pen class encapsulates various styles of pens like solid, dash, dash-dot, etc. We can change the style of pen using the DashStyle property of the Pen class. This is shown in the following statement.

p.DashStyle = DashStyle.Dash;

If we want, we can specify custom pen style by using the DashPattern property. There are several other properties of the Pen class that allow us to specify the pen type (hatch fill, gradient fill, solid color, etc), cap style, join style, etc.

Unlike GDI, GDI+ provides separate methods for rectangle and filled rectangle. To fill the rectangle we need to pass a Brush object. This is shown below.

HatchBrush hb=new HatchBrush(HatchStyle.BackwardDiagonal,
Color.Red, Color.Black);
g.FillRectangle (hb,200,20,150,100);

We have used hatch brush to fill the rectangle. The hatch brush is created using the HatchBrush class. We have mentioned the hatch style as BackwardDiagonal. The rectangle will get filled with the hatch brush in a red and black colour combination. Like the HatchBrush class there are several other classes used to fill the shapes with, namely, SolidBrush, TextureBrush, and LinearGradientBrush. Gradient brush is something that was not available in GDI. Let us see how to use it.

LinearGradientBrush gb=new LinearGradientBrush(ClientRectangle,
Color.BlanchedAlmond,Color.Aquamarine,90);
g.FillRectangle(gb,ClientRectangle);

Here, we have created an object of the LinearGradientBrush class and passed to its constructor the rectangle to be filled, and two colours that form the gradient pattern. The last parameter specifies the angle from which we wish to draw. Specifying 90 would fill the window vertically.

Coordinates and Transformations
In the Graphics methods we specify coordinates in a two-dimensional coordinate system. The system has the origin at the top-left corner and x and y axes point to the right and down respectively. All the methods take coordinates in pixels. The coordinates passed to Graphics methods are world coordinates. When we pass world coordinates to a method, they firstly get translated into page coordinates (logical coordinates) and then into device coordinates (physical coordinates). Ultimately, the shape gets drawn in device coordinates. In both the page and device coordinate system the measure of unit is the same—pixels. The coordinate system can be customised by shifting the origin to some other place in the client area and by setting a different measure of unit. Let us see how this can be achieved. We would first draw a horizontal line having 1 inch of width. Here is the code to do this.

private void Form1_Paint(object sender, PaintEventArgs e)
{
	Graphics g=e.Graphics;
	g.PageUnit=GraphicsUnit.Inch;
   Pen p=new Pen (Color.Green, 1/g.DpiX);
	g.DrawLine (p,0,0,1,0);
}

Here, firstly we have set the PageUnit property to GraphicsUnit.Inch specifying that the unit of measure is an inch. We have created a Pen object and set its width to 1 / g.Dpix. The Dpix property of the Graphics class indicates a value, in dots per inch, for the horizontal resolution supported by this Graphics object. Note that this is necessary because now Pen object also assumes 1 unit = 1 inch. So, if we don’t set the pen width like this, a line with 1 inch pen width would get drawn. Next we drew a line having one unit measure, which happens to be an inch.

Let us now shift the origin to the centre of the client area and draw the line again.

private void Form1_Paint (object sender, PaintEventArgs e)
{
	Graphics g = e.Graphics; 
   g.PageUnit = GraphicsUnit.Inch;
   g.TranslateTransform ( ( ClientRectangle.Width/g.DpiX )/ 2, 
   (ClientRectangle.Height/g.DpiY)/2);
   Pen p = new Pen ( Color.Green, 1/g.DpiX);
   g.DrawLine (p,0,0,1,0);
}

Here, after setting the unit to an inch using the PageUnit property, we have called the TranslateTransform( ) method to shift the origin to the centre of the client area. This method maps the world coordinates to page coordinates and so the transformation is called world transformation. The x and y values we have passed to the TranslateTransform( ) method get added to every x and y values we pass to the Graphics methods. Finally, we created a pen having proper width and drew the line.

GDI+ also allows us to orient the x and y axes’ direction to the specified angle. For this, it provides the RotateTransform( ) method. For example, if we call the RotateTransform( ) method before drawing the line as shown below,

g.RotateTransform(30);

then line would get displayed slanting downwards, 30 degrees below the base line. We can use this functionality of the RotateTransform( ) method to create an application like an analogue clock.

Disposing graphics objects
Whenever we open a file, we close it after we have finished working with the file. This is because a handle is associated with the file and it remains open if we don’t close it explicitly. Similarly, GDI+ resources like pens, brushes and fonts need to be disposed of because they encapsulate GDI+ handles in them. To release the GDI+ resources, we can call the Dispose( ) method on every object that is to be released. For example, the following statement would release the pen object represented by penobject using the Dispose( ) method.

penobject.Dispose();

We must also release the Graphics object obtained by calling the CreateGraphics() method.

Yashavant Kanetkar, one of the first Express Computer columnists, is an established software expert, speaker and author with several best-sellers to his credit, including titles like “Let Us C” and the “Fundas” series. Contact him at kanet@nagpur.dot.net.in
<Back to top>


© Copyright 2000: Indian Express Group (Mumbai, India). All rights reserved throughout the world. This entire site is compiled in
Mumbai by The Business Publications Division of the Indian Express Group of Newspapers.
Please contact our Webmaster for any queries on this site.