
CreateGraphics. A boon or a curse?For for some reason, the picture box control is one of the most misused in the windows forms toolbox. I think it has something to do with the technique used in a similarly named VB 6.0 control. This common mistake makes it the number one GDI+ problem and hence the most popular GDI+ FAQ question. Almost every time this question is asked it's very similar to that shown below; "When I draw on my picturebox control everything is shown the first time but the picturebox never refreshes my picture. Why??? Heres some code... private void OnButtonClick(object sender, EvetArgs e) { Graphics g=pictureBox1.CreateGraphics(); g.DrawEllipse(Brushes.Black,10,10,100,100); g.DrawRectangle(Brushes.Red,30,30,40,40); g.Dispose(); }"
The root of this problem is that the fundamental rules of windows programming have been broken. And as a consequence of the picture box is blamed for something that's really not its fault. To help explain why, the four points below outline what's gone wrong in this case.
The right way to do it.Following the rules of the event driven system is easy but requires a little forethought. So, if you want to draw some little bit of graphics and have it remain there when a window moves in front of it and away again or when you minimize and restore, you have to service the Paint event of whatever object it is that you wish to paint on. The PictureBox carries baggage around with it that is unnecessary for this kind of application. If you just want to draw something in one place, draw it on the form by responding to the Form.Paint event. If you want a handy placeholder for a graphic that works within a set bounds, use a Panel control and service it's Paint event. If you want to duplicate a graphic over and over for your corporate image, create a control and do the drawing in the OnPaint override. To illustrate the points made here, I've prepared a little application that does the following;
Listing 1. using System; using System.Drawing; using System.Collections; using System.ComponentModel; using System.Windows.Forms; using System.Data;
namespace RightWayDrawing { /// <summary> /// Summary description for Form1. /// </summary> public class Form1 : System.Windows.Forms.Form { private System.Windows.Forms.Button button1; private System.Windows.Forms.Panel panel1; /// <summary> /// Required designer variable. /// </summary> private System.ComponentModel.Container components = null;
bool _showGraphic=false;
public Form1() { // // Required for Windows Form Designer support // InitializeComponent();
// // TODO: Add any constructor code after InitializeComponent call // }
/// <summary> /// Clean up any resources being used. /// </summary> protected override void Dispose( bool disposing ) { if( disposing ) { if (components != null) { components.Dispose(); } } base.Dispose( disposing ); }
#region Windows Form Designer generated code /// <summary> /// Required method for Designer support - do not modify /// the contents of this method with the code editor. /// </summary> private void InitializeComponent() { this.button1 = new System.Windows.Forms.Button(); this.panel1 = new System.Windows.Forms.Panel(); this.SuspendLayout(); // // button1 // this.button1.Location = new System.Drawing.Point(88, 8); this.button1.Name = "button1"; this.button1.Size = new System.Drawing.Size(96, 23); this.button1.TabIndex = 0; this.button1.Text = "Toggle Graphic"; this.button1.Click += new System.EventHandler(this.button1_Click); // // panel1 // this.panel1.Location = new System.Drawing.Point(24, 56); this.panel1.Name = "panel1"; this.panel1.Size = new System.Drawing.Size(240, 200); this.panel1.TabIndex = 1; this.panel1.Paint += new System.Windows.Forms.PaintEventHandler(this.panel1_Paint); // // Form1 // this.AutoScaleBaseSize = new System.Drawing.Size(5, 13); this.ClientSize = new System.Drawing.Size(292, 266); this.Controls.Add(this.panel1); this.Controls.Add(this.button1); this.Name = "Form1"; this.Text = "Form1"; this.ResumeLayout(false);
} #endregion
/// <summary> /// The main entry point for the application. /// </summary> [STAThread] static void Main() { Application.Run(new Form1()); }
private void button1_Click(object sender, System.EventArgs e) { //in the button event we *ONLY* service the event and //tell the panel that something is different. _showGraphic=!_showGraphic; this.panel1.Invalidate(); }
private void panel1_Paint(object sender, System.Windows.Forms.PaintEventArgs e) { //in the Paint event we *ONLY* Paint!!! if(_showGraphic) { e.Graphics.FillEllipse(Brushes.Yellow,0,0,150,150); e.Graphics.FillEllipse(Brushes.Black,30,70,20,20); e.Graphics.FillEllipse(Brushes.Black,100,70,20,20); e.Graphics.FillEllipse(Brushes.Black,30,100,90,20); e.Graphics.FillEllipse(Brushes.Yellow,30,92,90,20); } }
} }
Copyright Robert W. Powell 2003. All rights reserved
|