Drawing with GDI+

GDI+ is responsible for two-dimensional graphics, imaging, and typography for the Windows operating system. The .NET Framework includes classes that act as a managed wrapper around GDI+, providing graphics capabilities for Windows Forms.

The features of GDI+ are similar to those of the Java 2D API included in the Java 2 platform; with some minor exceptions, the principles behind both technologies are the same, and knowledge of Java 2D can easily be translated to GDI+.

The System.Drawing.Graphics class represents a container on which GDI+ operations can be performed; this class is the equivalent of the java.awt.Graphics2D and java.awt.Graphics classes from the Java API.

Obtaining a Graphics Instance

The most common approach to obtaining an instance of System.Drawing.Graphics is to override the Control.OnPaint event handler, which is invoked when a control should repaint itself. The following example demonstrates this approach:

using System.Drawing;
using System.Windows.Forms;

public class SimpleForm :Form {

    static void Main() {
        Application.Run(new SimpleForm());
    }

    // Other methods, such as Dispose and a default
    // constructor, would go here.

    protected override void OnPaint(PaintEventArgs p_event) {
        Graphics x_graph = p_event.Graphics;
        // drawing operations
    }
}

The Graphics property of the PaintEventArgs class returns the System.Drawing.Graphics instance for the current control, to which GDI+ operations can be applied. The Paint event is raised automatically when a component should be redrawn or manually by calling the Control.RaisePaintEvent method.

Instances of System.Drawing.Graphics can also be obtained by calling the Control.CreateGraphics method. Drawing operations applied to the Graphics instance that is returned from this method take effect immediately, as opposed to waiting for the component to be repainted.

Lines, Shapes, and Curves

Unlike Java, the GDI+ Graphics class doesn’t maintain state information for drawing operations. For example, the Java java.awt.Graphics.setColor method specifies a color that will be used for subsequent drawing operations; specifying Color.Red means that all shapes and lines will be drawn in red until the color is changed.

By contrast, the .NET GDI+ classes require the programmer to specify the color settings as part of each draw method. The System.Drawing.Brush class is used to specify fill settings for solid shapes and the System.Drawing.Pen class to specify line settings.

The Brush class is abstract, and drawing operations are performed using a concrete implementation. Table 18-4 describes the brush implementations included in the .NET Framework.

Table 18-4. Brush Implementations

Brush Implementation

Description

System.Drawing.SolidBrush

A brush that uses a single color to fill the interior of a shape

System.Drawing.TextureBrush

A brush that uses an image to fill the interior of a shape

System.Drawing.Drawing2D.HatchBrush

A brush that uses a hatched-line pattern to fill the interior of a shape

System.Drawing.Drawing2D.LinearGradientBrush

A brush that fills the interior of a shape using a gradient between two or more colors

The following example demonstrates how to use a SolidBrush to fill a rectangle. The SolidBrush constructor accepts a value from the System.Drawing.Color structure, which is equivalent to the java.awt.Color class:

Graphics x_graphics = CreateGraphics();
Brush x_brush = new SolidBrush(Color.Red);
x_graphics.FillRectangle(x_brush, 10, 10, 50, 50);

The sealed System.Drawing.Pen class is used to specify properties for drawing lines and shapes. The constructor for the class accepts a Color value and an optional line width; the width defaults to 1 pixel if not specified. The following code fragment demonstrates how to use a Pen to draw a line:

Graphics x_graphics = CreateGraphics();
Pen x_pen = new Pen(Color.Green, 2);
x_graphics.DrawLine(x_pen, 10, 10, 50, 50);

The System.Drawing.Pens class contains properties that can be used to obtain Pen instances for all of the colors specified in the System.Drawing.Color structure; each of the instances has a width of 1 pixel. The statements in the following code fragment are equivalent:

Pen x_pen = new Pen(Color.Green, 1);
Pen x_pen = Pens.Green;

The Pen class defines members that allow a great deal of control over how a line is drawn. Table 18-5 summarizes these members; consult the .NET documentation for more information.

Table 18-5. System.Drawing.Pen Members

Member

Description

Alignment

When a shape is drawn, the Alignment property specifies whether the line should be drawn centered or inside the border of the shape; applies to lines more than 1 pixel wide.

Color

The color (from the System.Drawing.Color structure) used to draw lines.

DashCap

Specifies the way that the ends of dashed lines will be drawn using the DashCap enumeration. Defaults to DashCap.Flat.

DashOffset

Specifies the distance from the start of a line to begin dashing.

DashStyle

Specifies the dashing style for a line using the DashStyle enumeration. Defaults to DashStyle.Solid but also supports dots and dashes.

EndCap StartCap

Specifies the cap that will be drawn at the start or end of a line. Defaults to LineCap.Flat but can also be rounded, triangular, and square.

LineJoin

Specifies the way two lines are joined together when drawn as part of a shape. Defaults to LineJoin.Miter but can also be beveled or rounded.

Width

Specifies the width of the line in pixels.

Table 18-6 summarizes the members in the java.awt.Graphics and System.Drawing.Graphics2D classes used for drawing lines, shapes and curves.

Table 18-6. Comparison of Graphics Members

Java

.NET

Comments

draw3DRect()

N/A

 

drawArc()

DrawArc()

 

N/A

DrawBezier()

Draws a Bézier curve using four System.Drawing.Point instances. Similar functionality is available in Java through the java.awt.geom.GeneralPath class.

N/A

DrawBeziers()

Draws a series of Bézier curves using an array of System.Drawing.Point structures.

N/A

DrawClosedCurve()

Draws a closed curve through an array of Point structures.

N/A

DrawCurve()

Draws an open curve through an array of Point structures.

drawLine()

DrawLine()

 

N/A

DrawLines()

Draws a series of lines that connect a set of Point structures. Similar functionality is available in Java through the java.awt.geom.GeneralPath class.

drawOval()

DrawEllipse()

 

N/A

DrawPie()

Draws a pie-shaped segment.

drawPolygon()

DrawPolygon()

 

drawRect()

drawRoundRect()

DrawRectangle()

The effect of a round rectangle can be achieved by using the LineJoin property of the Pen class.

N/A

DrawRectangles()

Draws a series of rectangles.

fill3DRect()

N/A

 

fillArc()

N/A

 

fillOval()

FillEllipse()

 

fillPolygon()

FillPolygon()

 

N/A

FillPie()

 

fillRect()

fillRoundRect()

FillRectangle()

The effect of a round rectangle can be achieved by using the LineJoin property of the Pen class.

Drawing Strings

The GDI+ approach to drawing text follows a model similar to that of the support for lines and shapes. The System.Drawing.Graphics class doesn’t maintain state information for font or color, so settings must be passed into the drawing method using the Font and Brush classes with each call. The following example demonstrates how to draw a string using the Graphics.DrawString method, which is functionally equivalent to the java.awt.Graphics.drawString method:

Graphics x_graphics = CreateGraphics();

String x_string = "C# for Java Developers";
Font x_font = new Font("TimesRoman", 14);
SolidBrush x_brush = new SolidBrush(Color.Green);

StringFormat x_format = new StringFormat();
x_format.FormatFlags = StringFormatFlags.DirectionVertical;

x_graphics.DrawString(x_string, x_font, x_brush, 10.0F, 20.0F, x_format);

Table 18-7 details the arguments supplied to the Graphics.DrawString method.

Table 18-7. Arguments for the System.Drawing.Graphics.DrawString Method

Argument

Description

System.String

The character string to draw.

System.Drawing.Font

The font to use to draw the string.

System.Drawing.Brush

The details of the character fill settings and colors.

(float,float)

System.Drawing.PointF

System.Drawing.RectangleF

The location at which to draw the string. The location always refers to the upper left corner of the drawn text but can be expressed as a pair of floating-point numbers, a PointF, or a RectangleF.

System.Drawing.StringFormat

Optional argument that specifies the format of the drawn text, including spacing and alignment.

Drawing Images

The GDI+ managed classes support images through the abstract System.Drawing.Image class, equivalent to java.awt.Image. The .NET Framework provides two concrete implementations of the Image class, System.Drawing.Bitmap and System.Drawing.Imaging.Metafile.

The Bitmap class is responsible for managing bitmap images. GDI+ supports the following formats:

  • Windows Bitmap Image Format (BMP)

  • Graphics Interchange Format (GIF)

  • Joint Photographic Experts Group (JPEG)

  • Exchangeable Image File (EXIF)

  • Portable Network Graphics (PNG)

  • Tag Image File Format (TIFF)

The Metafile class is responsible for vector images, which are represented by a sequence of drawing commands. The Metafile class supports the following formats:

  • Windows Metafile (WMF)

  • Enhanced Metafile (EMF)

  • Enhanced Metafile Plus (EMF+)

An image can be loaded from a file either by using the constructors of the Bitmap or Metafile class or by using the static FromFile method in the Image class.

Images are drawn onto a Graphics instance using the DrawImage method; this method provides extensive support for scaling and cropping images by providing 30 different overloaded forms. Consult the .NET documentation for details of these members.

The following example demonstrates loading and painting a bitmap, which is contained in the current working directory:

Graphics x_graphics = CreateGraphics();
Bitmap x_bitmap = new Bitmap("myImage.jpg");
x_graphics.DrawImage(x_bitmap, 0, 0);

Double Buffering

GDI+ causes the Graphics class to update the screen after every drawing operation, which can be seen by the user as screen flicker; this flickering can be eliminated by a technique known as double buffering, whereby the drawing operations are applied to a Graphics instance held in memory and then copied to the screen in a single operation.

Double buffering can be enabled by using the SetStyle method from the System.Windows.Forms.Control class; this method accepts an argument from the System.Windows.Forms.ControlStyles enumeration, as shown in the following code fragment:

SetStyle(ControlStyles.DoubleBuffer, true);

Flickering can also occur because the contents of a Graphics instance are cleared automatically before a component is asked to repaint itself. This feature can be disabled by specifying the ControlStyles.UserPaint and ControlSyles.AllPaintingInWmPaint values in the SetStyle method. The following statement demonstrates how to completely eliminate flicker:

SetStyle(ControlStyles.DoubleBuffer |
    ControlStyles.UserPaint |
    ControlStyles.AllPaintingInWmPaint, true);

Double buffering can also be performed programmatically by executing drawing operations on an in-memory bitmap, as shown in the following example:

protected override void OnPaint(PaintEventArgs p_event) {
    Bitmap x_bitmap = new Bitmap(Width, Height);
    Graphics x_offscreen = Graphics.FromImage(x_bitmap);
    // drawing operations

    p_event.Graphics.DrawImage(x_bitmap, 0, 0);
    x_bitmap.Dispose();
}

The Bitmap instance is created by specifying the dimensions of the area to draw; in the example, we use the Width and Height properties from the Control class. The off-screen Graphics instance is retrieved from the Bitmap, and the drawing operations are then applied without causing the screen to be updated. Finally, the contents of the Bitmap are drawn to the screen using the Graphics.DrawImage method; it’s important to ensure that the Dispose method is called on the Bitmap to ensure that unmanaged resources are released.

The flicker caused by the automatic clearing of the contents of a specific component can be prevented by overriding the Control.OnPaintBackground method and providing an empty method body.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset