Have a question? ask www.kenlet.com
Home  |  FAQ  |  About  |  Contact  |  View Source   
 
SEARCH:
 
BROWSE:
    My Hood
Edit My Info
View Events
Read Tutorials
Training Modules
View Presentations
Download Tools
Scan News
Get Jobs
Message Forums
School Forums
Member Directory
   
CONTRIBUTE:
    Sign me up!
Post an Event
Submit Tutorials
Upload Tools
Link News
Post Jobs
   
   
Home >  Tutorials >  C# >  Drawing with the .NET Framework
Add to MyHood
Drawing with the .NET Framework   [ printer friendly ]
Stats
  Rating: 4.44 out of 5 by 18 users
  Submitted: 10/14/01
Shawn Farkas ()

 
The System.Drawing namespace contains tools that you can use to draw images directly onto any control in a Windows Forms application. This tutorial will show you how to get started by drawing a smiling face onto the main form of an application.

The Graphics Object

In order to do any drawing with the .NET framework, you need to obtain a graphics object. The Graphics class defines all the drawing functions that you can use to draw lines, ellipses, arcs, etc. These methods come in two forms Drawxxx and Fillxxx. The Draw functions draw an outline of a shape, while the Fill functions will draw a solid shape.

One thing to be aware of is the coordinate system. Point (0,0) is actually in the upper left corner of your drawing area, larger x values give points more to the right, and larger y values give points more to the bottom of the area. Another point to be aware of is that in the Beta 2 documentation, most of the drawing methods are listed as requiring the lower right point of the drawing, however the point that should be passed to them is the upper left one.

Graphics objects cannot be created directly with the new keyword, instead they must be created through a static method on the Graphics class itself. There are three methods that could be used, depending on your needs. Graphics.FromImage() will create a graphics object from an Image. Likewise Graphics.FromHdc() and Graphics.FromHwnd() will create graphics objects from a device context handle and a window handle respectively.

When drawing on a control or a form, the Graphics.FromHwnd() method should be used. The window handle for the object that you want to draw on can be obtained through that object’s public Handle property. Once you are done using the Graphics object, you must make sure to dispose of it either through the C# using construct or by calling its Dispose() method. This will free up any GDI resources allocated by the object.

Pens and Brushes

In order to use a Graphics object to draw, you will also need either a pen or a brush. Pens are used to draw outlines of shapes, while brushes are used to create filled in shapes. Both pens and brushes create GDI objects in Windows, so they need to be disposed of when you are done with them, in order to free these objects.

Pens are created by specifying a color and the width of the line the pen should create. You cannot create a brush directly, since it is an abstract class. Instead you must choose one of the following kinds of brushes.

  • HatchBrush - fills with a hatch pattern specified by a member of the HatchStyle enumeration
  • LinearGradientBrush - fills by blending from a starting color at one side to an ending color on the other
  • PathGradientBrush - fills from blending from a color at the center to a color on the outer edge
  • SolidBrush - fills in a solid color
  • TextureBrush.- fills with an image

Sample Code

All sample code given here was tested with Beta 2 of the .NET Framework. The code needs to reference System.Windows.Forms and System.Drawing to compile. In Visual Studio .NET you would add a these assemblies to your project’s references. If you choose to compile the sample code on the command line, you would use a command similar to this:
csc smile.cs /r:System.Windows.Forms.dll /r:System.Drawing.dll

The structure of the sample program is quite simple. The code consists of one class, Smile, which inherits from the System.Windows.Forms.Form class. The Main() function of this class, simply instantiates one instance of Smile and starts it running.

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


The constructor for the Smile class takes care of some basic WinForms initialization like setting up the form title and size. It also adds an event handler for the form’s paint event. By responding to the paint event, the application can repaint the window by drawing the face onto it.

public Smile()
{
    Size = new System.Drawing.Size(350,350);
    Text = "Smile";

    Paint += new PaintEventHandler(Form_Paint);
    return;
}


Form_Paint() handles paint messages delivered to the main window. The implementation is very basic, it just passes a Graphics object that represents the window to the DrawFace() function.

public void Form_Paint(object o, PaintEventArgs args)
{
    using(Graphics drawingSurface = Graphics.FromHwnd(Handle))
        DrawSmile(drawingSurface);

    return;
}


All the real work of this program is done in the DrawSmile() method. It first creates a yellow brush to paint the head of the face with, and draws a circular ellipse. Then a black brush is created and the two eyes are drawn over the top of the face. Finally, I use a 10 pixel wide black pen to draw the arc representing the mouth.

private void DrawSmile(Graphics drawingSurface)
{
    using(Brush yellowBrush = new SolidBrush(Color.Yellow))
        drawingSurface.FillEllipse(yellowBrush, 25, 25, 187, 187);

    using(Brush blackBrush = new SolidBrush(Color.Black))
    {
        drawingSurface.FillEllipse(blackBrush, 70, 75, 22, 17);
        drawingSurface.FillEllipse(blackBrush, 140, 75, 22, 17);
    }

    using(Pen blackPen = new Pen(Color.Black, 10))
        drawingSurface.DrawArc(blackPen, 65, 95, 102, 75, 0, 180);

    return;
}


Smile.cs:

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

public class Smile : Form
{
    public Smile()
    {
        Size = new System.Drawing.Size(350,350);
        Text = "Smile";

        this.Paint += new PaintEventHandler(Form_Paint);

        return;
    }

    public void Form_Paint(object o, PaintEventArgs args)
    {
        using(Graphics drawingSurface = Graphics.FromHwnd(Handle))
            DrawSmile(drawingSurface);

        return;
    }

    private void DrawSmile(Graphics drawingSurface)
    {
        using(Brush yellowBrush = new SolidBrush(Color.Yellow))
            drawingSurface.FillEllipse(yellowBrush, 25, 25, 187, 187);

        using(Brush blackBrush = new SolidBrush(Color.Black))
        {
            drawingSurface.FillEllipse(blackBrush, 70, 75, 22, 17);
            drawingSurface.FillEllipse(blackBrush, 140, 75, 22, 17);
        }

        using(Pen blackPen = new Pen(Color.Black, 10))
            drawingSurface.DrawArc(blackPen, 65, 95, 102, 75, 0, 180);

        return;
    }

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


Double Buffering

This application runs fine, but there is one small problem. If you resize the window quickly, there is a noticeable flicker as the face redraws itself. This flicker can be handled by employing double buffering. Double buffering is a technique where the image that is to be displayed is drawn in a buffer in memory and then once it is fully constructed, it is placed on the screen. Double buffering is easy to accomplish with the .NET framework. Instead of using a buffer in memory, a bitmap can be created. This bitmap exists only in memory, and is never persisted to the disk. Every time the window is asked to paint itself, the bitmap is erased, and then drawn into again. Once it is drawn, it is painted onto the main form.

All of these changes can be done in the Form_Paint() method. First a Bitmap is created, and a Graphics object is created to draw on it. Then the DrawFace() method is called, except instead of passing it the Graphics object created for the window, it is passed the Graphics object created for the bitmap. Once the face is drawn into the bitmap, it is painted into the window using the DrawImage() method.

public void Form_Paint(object o, PaintEventArgs args)
{
    Bitmap buffer = new Bitmap(350, 350);

    using(Graphics bufferSurface = Graphics.FromImage(buffer))
        DrawSmile(bufferSurface);

    using(Graphics drawingSurface = Graphics.FromHwnd(Handle))
        drawingSurface.DrawImage(buffer, 0, 0, 350, 350);

    return;
}


Return to Browsing Tutorials

Email this Tutorial to a Friend

Rate this Content:  
low quality  1 2 3 4 5  high quality

Reader's Comments Post a Comment
 
Interesting Article
-- A Vallur, January 29, 2002
 
Good work; no matter what language I use, I'm always keen on knowing how to draw... your tutorial was written very well, although there are some .NETy things in the code fragments which I'm not familiar with yet.
-- Daniel Bigham, February 17, 2002
 
A good tutorial.
-- Brian Simoneau, March 01, 2002
 
Great job!
-- Kuniaki Tran, March 03, 2002
 
Very nice tutorial. I did some Java 2D drawing before and it's very similar to the C# drawing, just that Java still sucks and I don't like it so I'm going to be using C# =)
-- Victor Vuong, March 04, 2002
 
Great Job Shawn!
-- Sean Fitzgerald, March 14, 2002
 
is there some way to store a Shape or polygon, similar to java.awt.shape ??
http://java.sun.com/j2se/1.4/docs/api/java/awt/Shape.html
-- Brian Armstrong, February 06, 2003
 
Copyright © 2001 DevHood® All Rights Reserved