Getting Graphics to stay on a Form (C#)

If you draw graphics onto a form, they may be lost when the form — or sections of the form — refreshes. This program shows one way to retain the graphics on the form background.

The program included here, named GraphicsTest, uses a simple Windows form with three buttons. Two of the buttons display graphics in the window and the third exits the program. This is a modification of a larger listing from my book, Teach Yourself the C# Language in 21 Days".

When you click the different buttons, shapes are drawn on the window's background. Figures 1 to 3 show some results. Because the location and the size of shapes are random, your output will be different. If you click a button again, more shapes will be drawn.

Figure 1 The GraphicsTest form.

Figure 2 - Output from GraphicsTest.

Figure 3 - Output from GraphicsTest.

I'm not providing a complete analysis for the listing; however, a couple comments deserve to be made.

This program uses a set of classes used to create and draw graphics. The graphics are drawn onto a basic graphics object named DrawingArea. This is a simple bitmap image that was declared in Line 14. All of the graphics are drawn onto this bitmap rather than directly to the form. The bitmap is then copied to the form. If you draw directly to the form, the graphics may be lost when the form is refreshed.

Stepping back, you'll see that in Line 4, the System.Drawing namespace is included. This namespace contains many of the graphic routines. Also included are a number of other namespaces, including Windows.Forms, which contains information for doing the Windows form logic.

In Lines 12 to 21, a number of variables are declared that will be used in drawing the graphics and creating controls on the form. Line 20 contains a variable for getting random numbers. In Line 21, myPen is declared as a Pen object. This object will be assigned colors and used to draw shapes later in the listing. In Line 27, you see a new Pen object actually created and the color blue is assigned to it. You can assign any color to the pen.

NOTE: Lots of colors are listed in the Color enumeration. You can assign them in the same way that the color blue was assigned. You can see a list of names for the many available colors at the end of this article.

In Lines 102 to 121, you can see the method btnLine_Click defined. This is actually an event that is executed when the line button is clicked. Because the color of the pen could have been changed, in Line 112, the pen defined earlier is set to the color blue. Before that, in Line 1105, a graphics object was created and assigned the DrawingArea graphic created earlier. This new graphic, oGraphics, will be used to draw upon.

In Lines 109 to 117, there is a loop that executes 50 times. This loop draws a single line each time through the loop by calling the DrawLine method in the graphics object that was created. The parameters being passed are not as complicated as they look in Lines 113 to 116. The first parameter is the pen, myPen. The next four parameters are random numbers. The first and third are numbers between 0 and the width of the form. The second and fourth are between 0 and the height of the form. The first two numbers are the starting point of the line. The last two are the ending point.

After the lines have been drawn, calling the Dispose method cleans up the oGraphics object. This is done in Line 118. Because the graphics object uses a lot of system resources, it is good to force this clean up.

The disposal of the graphics object is followed by a call to this.Invalidate in Line 120. Invalidate makes the current form redraw itself. This causes a paint event to occur. An event handler is created in Lines 185 to 198 for the painting event. In this method, the DrawingArea image is copied to the form's background image.

The other method events in this listing operate in much the same as in the earlier line listing: Random numbers are used to draw shapes. One other difference is in Lines 134 to 1137. In these lines, instead of setting the pen to a specific color, it is set to a random color. The FromArgb method sets red, green, and blue values for a single color. Because random numbers are used, the result is a random color.

This is a fun listing to play with. You should be able to change the colors, modify the shape sizes and locations, and work with these basic graphics. If you check out the listing in my book, you will find that rectangles and a solid color are added to the listing.

Listing GraphicsTest.cs — A Program to Draw Colored Shapes on a form.

001: // GraphicsTest.cs
002: //
003: using System;
004: using System.Drawing;
005: using System.ComponentModel;
006: using System.Windows.Forms;
007: 
008: namespace GraphicsTest
009: {
010:    public class frmGraphics : System.Windows.Forms.Form
011:    {
012:       private Bitmap DrawingArea;  // Area to draw on.
013: 
014:       private Button btnCircle;
015:       private Button btnLine;
016:       private Button btnOK;
017: 
018:       private System.ComponentModel.Container components = null;
019:       
020:       private System.Random rnd;
021:       private Pen myPen;
022: 
023:       public frmGraphics()
024:       {
025:          InitializeComponent();
026:          rnd   = new System.Random();
027:          myPen = new Pen(Color.Blue);
028:       }
029: 
030:       protected override void Dispose( bool disposing )
031:       {
032:          if( disposing )
033:          {
034:             if (components != null) 
035:             {
036:                components.Dispose();
037:             }
038:          }
039:          base.Dispose( disposing );
040:       }
041: 
042:       private void InitializeComponent()
043:       {
044:          this.btnCircle = new System.Windows.Forms.Button();
045:          this.btnLine = new System.Windows.Forms.Button();
046:          this.btnOK = new System.Windows.Forms.Button();
047:          this.SuspendLayout();
048:          // 
049:          // btnCircle
050:          // 
051:          this.btnCircle.Location = new System.Drawing.Point(8, 32);
052:          this.btnCircle.Name = "btnCircle";
053:          this.btnCircle.Size = new System.Drawing.Size(40, 40);
054:          this.btnCircle.TabIndex = 0;
055:          this.btnCircle.Text = "Circ";
056:          this.btnCircle.Click += new System.EventHandler(
057:                                         this.btnCircle_Click);
058:          // 
059:          // btnLine
060:          // 
061:          this.btnLine.Location = new System.Drawing.Point(8, 88);
062:          this.btnLine.Name = "btnLine";
063:          this.btnLine.Size = new System.Drawing.Size(40, 40);
064:          this.btnLine.TabIndex = 1;
065:          this.btnLine.Text = "Line";
066:          this.btnLine.Click += new System.EventHandler(this.btnLine_Click);
067:          // 
068:          // btnOK
069:          // 
070:          this.btnOK.Location = new System.Drawing.Point(296, 296);
071:          this.btnOK.Name = "btnOK";
072:          this.btnOK.TabIndex = 0;
073:          this.btnOK.Text = "OK";
074:          this.btnOK.Click += new System.EventHandler(this.btnOK_Click);
075:          // 
076:          // frmGraphics
077:          // 
078:          this.AutoScaleBaseSize = new System.Drawing.Size(5, 13);
079:          this.ClientSize = new System.Drawing.Size(376, 334);
080:          this.Controls.Add(this.btnOK);
081:          this.Controls.Add(this.btnLine);
082:          this.Controls.Add(this.btnCircle);
083:          this.FormBorderStyle = FormBorderStyle.Fixed3D;
084:          this.Name = "frmGraphics";
085:          this.Text = "Drawing";
086:          this.Load += new System.EventHandler(this.frmGraphics_Load);
087:          this.Closed += new System.EventHandler(this.frmGraphics_Closed);
088:          this.Paint += new System.Windows.Forms.PaintEventHandler(
089:                                     this.frmGraphics_Paint);
090:          this.ResumeLayout(false);
091: 
092:       }
093: 
094:       /// 
095:       /// The main entry point for the application.
096:       /// 
097:       public static void Main() 
098:       {
099:          Application.Run(new frmGraphics());
100:       }
101: 
102:       private void btnLine_Click(object sender, System.EventArgs e)
103:       {
104:          Graphics oGraphics;
105:          oGraphics = Graphics.FromImage(DrawingArea);
106: 
107:          myPen.Color = Color.Blue;
108: 
109:          for ( int x = 1; x < 50; x++)
110:          {
111:             oGraphics.DrawLine(
112:                      myPen, 
113:                     (int) rnd.Next(0, this.Width), 
114:                     (int) rnd.Next(0, this.Height),
115:                     (int) rnd.Next(0, this.Width),
116:                     (int) rnd.Next(0, this.Height));
117:          }
118:          oGraphics.Dispose();
119: 
120:          this.Invalidate();
121:       }
122: 
123: 
124:       private void btnCircle_Click(object sender, System.EventArgs e)
125:       {
126:          Graphics oGraphics;
127:          oGraphics = Graphics.FromImage(DrawingArea);
128: 
129:          // get a radius for circle - up to 1/2 the width of form
130:          int radius = rnd.Next(0, (this.Width / 2));  
131: 
132:          for ( int x = 1; x < 50; x++)
133:          {
134:             myPen.Color = Color.FromArgb( 
135:                (rnd.Next(0,255)), 
136:                (rnd.Next(0,255)),
137:                (rnd.Next(0,255)));
138: 
139:             oGraphics.DrawEllipse(
140:                myPen, 
141:                rnd.Next(0, this.Width),
142:                rnd.Next(0, this.Height),
143:                radius, radius);
144:          }
145:          oGraphics.Dispose();
146: 
147:          this.Invalidate();
148:       }
149: 
150:       private void btnOK_Click(object sender, System.EventArgs e)
151:       {
152:          Application.Exit();
153:       }
154: 
155:       private void frmGraphics_Load(object sender, System.EventArgs e)
156:       {
157:          DrawingArea = new Bitmap(
158:                  this.ClientRectangle.Width, 
159:                  this.ClientRectangle.Height,
160:                  System.Drawing.Imaging.PixelFormat.Format24bppRgb);
161:          InitializeDrawingArea();
162:       }
163: 
164:       private void InitializeDrawingArea()
165:       {
166:          Graphics oGraphics;
167:          oGraphics = Graphics.FromImage(DrawingArea);
168: 
169:          myPen.Color = Color.AliceBlue;
170: 
171:          for ( int x = 0; x < this.Width; x++)
172:          {
173:             oGraphics.DrawLine(myPen, x, 0, x, this.Height);
174:          }
175:          oGraphics.Dispose();
176:       
177:          this.Invalidate();
178:       }
179: 
180:       private void frmGraphics_Closed(object sender, System.EventArgs e)
181:       {
182:          DrawingArea.Dispose();
183:       }
184: 
185:       private void frmGraphics_Paint( object sender, 
186:                                       System.Windows.Forms.PaintEventArgs e)
187:       {
188:          Graphics oGraphics;
189: 
190:          oGraphics = e.Graphics;
191: 
192:          oGraphics.DrawImage( DrawingArea, 
193:                               0, 0, 
194:                               DrawingArea.Width, 
195:                               DrawingArea.Height);
196:          oGraphics.Dispose();
197:       }
198:    }
199: }

Color Table

AliceBlue        AntiqueWhite        Aqua       Aquamarine       Azure       Beige       Bisque       Black       BlanchedAlmond       Blue       BlueViolet       Brown       BurlyWood       CadetBlue       Chartreuse       Chocolate       Coral       CornflowerBlue       Cornsilk       Crimson       Cyan       DarkBlue       DarkCyan       DarkGoldenrod       DarkGray       DarkGreen       DarkKhaki       DarkMagenta       DarkOliveGreen       DarkOrange       DarkOrchid       DarkRed       DarkSalmon       DarkSeaGreen       DarkSlateBlue       DarkSlateGray       DarkTurquoise       DarkViolet       DeepPink       DeepSkyBlue       DimGray       DodgerBlue       Firebrick       FloralWhite       ForestGreen       Fuchsia       Gainsboro       GhostWhite       Gold       Goldenrod       Gray       Green       GreenYellow       Honeydew       HotPink       IndianRed       Indigo       Ivory       Khaki       Lavender       LavenderBlush       LawnGreen       LemonChiffon       LightBlue       LightCoral       LightCyan       LightGoldenrodYellow       LightGray       LightGreen       LightPink       LightSalmon       LightSeaGreen       LightSkyBlue       LightSlateGray       LightSteelBlue       LightYellow       Lime       LimeGreen       Linen       Magenta       Maroon       MediumAquamarine       MediumBlue       MediumOrchid       MediumPurple       MediumSeaGreen       MediumSlateBlue       MediumSpringGreen       MediumTurquoise       MediumVioletRed       MidnightBlue       MintCream       MistyRose       Moccasin       NavajoWhite       Navy       OldLace       Olive       OliveDrab       Orange       OrangeRed       Orchid       PaleGoldenrod       PaleGreen       PaleTurquoise       PaleVioletRed       PapayaWhip       PeachPuff       Peru       Pink       Plum       PowderBlue       Purple       Red       RosyBrown       RoyalBlue       SaddleBrown       Salmon       SandyBrown       SeaGreen       SeaShell       Sienna       Silver       SkyBlue       SlateBlue       SlateGray       Snow       SpringGreen       SteelBlue       Tan       Teal       Thistle       Tomato       Transparent       Turquoise       Violet       Wheat       White       WhiteSmokeYellow       YellowGreen

Downloads

Download demo project - 3 Kb
Download source - 3 Kb


About the Author

Bradley Jones

Bradley Jones, in addition to managing CodeGuru, Brad! oversees the Developer.com Newtwork of sites including Codeguru, Developer.com, DevX, VBForums, and over a dozen more with a focus on software development and database technologies. His experience includes development in C, C++, VB, some Java, C#, ASP, COBOL, and more as well as having been a developer, consultant, analyst, lead, and much more. His recent books include Teach Yourself the C# Language in 21 Days, Web 2.0 Heroes, and Windows Live Essentials and Services.
Google+ Profile | Linked-In Profile | Facebook Page

Comments

  • Possible bug

    Posted by dcell59 on 01/15/2007 05:27pm

    Line 196 disposes of a Graphics object that was not created by the program. Is this correct?

    Reply
  • flicker-free update

    Posted by AndyZZ on 07/11/2005 01:12pm

    Helpful article, but add this.SetStyle(ControlStyles.Opaque, true); after InitializeComponent() for flicker free updates

    Reply
  • Question

    Posted by Legacy on 02/19/2004 12:00am

    Originally posted by: Himmett

    Is it possible that a drawing object can be drawn as a true object that can receive mouse events?

    Thanks
    Himmett

    Reply
Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • On-demand Event Event Date: September 10, 2014 Modern mobile applications connect systems-of-engagement (mobile apps) with systems-of-record (traditional IT) to deliver new and innovative business value. But the lifecycle for development of mobile apps is also new and different. Emerging trends in mobile development call for faster delivery of incremental features, coupled with feedback from the users of the app "in the wild." This loop of continuous delivery and continuous feedback is how the best mobile …

  • Packaged application development teams frequently operate with limited testing environments due to time and labor constraints. By virtualizing the entire application stack, packaged application development teams can deliver business results faster, at higher quality, and with lower risk.

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds