[C# Helper]
Index Books FAQ Contact About Rod
[Beginning Database Design Solutions, Second Edition]

[Beginning Software Engineering, Second Edition]

[Essential Algorithms, Second Edition]

[The Modern C# Challenge]

[WPF 3d, Three-Dimensional Graphics with WPF and C#]

[The C# Helper Top 100]

[Interview Puzzles Dissected]

[C# 24-Hour Trainer]

[C# 5.0 Programmer's Reference]

[MCSD Certification Toolkit (Exam 70-483): Programming in C#]

Title: Let the user scribble on a background image in C#

[Let the user scribble on a background image in C#]

The post Let the user scribble on a PictureBox in C# shows how you can let the user draw with the mouse. This example lets you load a background image. It also lets you save the result into an image file.

Loading a Background Image

There are only two basic changes that you need to make to scribble on a background image. First, set the PictureBox control's Image property to the image. Second, do not clear the control in the Paint event handler. This example also takes a few other actions to make the program more user-friendly.

When you use the File menu's Load Background Image command, the following code executes.

private void mnuFileLoadBgImage_Click(object sender, EventArgs e) { if (ofdBackground.ShowDialog() == DialogResult.OK) { picCanvas.SizeMode = PictureBoxSizeMode.AutoSize; picCanvas.Anchor = AnchorStyles.Top | AnchorStyles.Left; picCanvas.Image = LoadBitmapUnlocked(ofdBackground.FileName); } }

This code displays a FileSelectionDialog. If you select an image file, the method sets the picCanvas control's SizeMode property to AutoSize so it resizes to fit its picture. It also sets the control's Anchor property to Top, Left so the control will not resize when the form resizes.

The code then displays the image in the PictureBox control's Image property.

For information about the LoadImageUnlocked method, see Load images without locking their files in C#.

Starting a New Scribble

When you invoke the File menu's New command, the following code executes.

// Start a new drawing. private void mnuFileNew_Click(object sender, EventArgs e) { Polylines = new List<List<Point>>(); picCanvas.Image = null; int margin = picCanvas.Left; int width = ClientSize.Width - 2 * margin; int height = ClientSize.Height - picCanvas.Top - margin; picCanvas.SizeMode = PictureBoxSizeMode.Normal; picCanvas.Size = new Size(width, height); picCanvas.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right; picCanvas.Refresh(); }

This code creates a new Polylines list to remove all of the old scribbles. It then sets the picCanvas control's SizeMode property to Normal so it can resize when the form resizes. The code also resizes the control so it fills the form nicely. The event handler finishes by setting the control's Anchor property so it resizes when the form resizes.

Drawing the Scribbles

The following code draws the scribbles.

// Redraw. private void picCanvas_Paint(object sender, PaintEventArgs e) { e.Graphics.SmoothingMode = SmoothingMode.AntiAlias; // Draw the polylines. foreach (List<Point> polyline in Polylines) { e.Graphics.DrawLines(Pens.Black, polyline.ToArray()); } }

This code is very similar to the code used by the previous version of the program. The only difference is that this version does not call e.Graphics.Clear before it draws. If it did call Clear, that would erase the image displayed in the background.

As you can see if you run the program, this example doesn't need the call to Clear. I put it in the previous example mostly out of habit. You would need that call if the Paint event handler draws something that should move or resize when the PictureBox resizes. For example, suppose you want to draw an ellipse that just fills the PictureBox. Then you would need to call Clear before drawing so it can erase any previous ellipses that were drawn when the form had a different size.

Saving the Result

When you select the File menu's Save command, the following code executes.

private void mnuFileSave_Click(object sender, EventArgs e) { if (sfdResult.ShowDialog() == DialogResult.OK) { Bitmap bm = GetControlImage(picCanvas); SaveImage(bm, sfdResult.FileName); } }

This code displays a SaveFileDialog. If you select a destination file and click Save, the code calls the GetControlImage method to get an image of the PictureBox. It then uses the SaveImage method to save the image with an appropriate file format. For example, if the file name's extension is png, then SaveImage saves the image as a PNG file.

The following code shows the GetControlImage method.

// Return a Bitmap holding an image of the control. private Bitmap GetControlImage(Control ctl) { Bitmap bm = new Bitmap(ctl.Width, ctl.Height); ctl.DrawToBitmap(bm, new Rectangle(0, 0, ctl.Width, ctl.Height)); return bm; }

This code makes a bitmap large enough to hold the image. It then calls the control's DrawToBitmap method to draw the control onto the bitmap and returns the result.

For more information on the SaveImage method, see the post Save images with an appropriate format depending on the file name's extension in C#.

Conclusion

Displaying an image behind a drawing is fairly easy. Just set the PictureBox control's Image property and don't call Clear in the Paint event handler. This is an important technique and a lot of people don't know about it, but the example demonstrates a couple of other useful techniques such as setting a PictureBox control's SizeMode and Anchor properties.

For other examples that improve the basic scribble program, see these posts:

Download the example to experiment with it and to see additional details.

© 2009-2023 Rocky Mountain Computer Consulting, Inc. All rights reserved.