Title: Draw random rectangles in C#
This example simply draws random rectangles on top of each other. It's mostly straightforward, although it does contain a couple of techniques that are useful if you do a lot of graphics programming.
When it starts, the following code performs a few initialization tasks.
private Bitmap Bm;
private Graphics Gr;
// Make a bitmap to display.
private void Form1_Load(object sender, EventArgs e)
{
FormBorderStyle = FormBorderStyle.FixedDialog;
MinimizeBox = false;
MaximizeBox = false;
DoubleBuffered = true;
// Set at design time:
// StartPosition = FormStartPosition.CenterScreen;
Bm = new Bitmap(ClientSize.Width, ClientSize.Height);
Gr = Graphics.FromImage(Bm);
BackgroundImage = Bm;
}
This code sets the form's BorderStyle property to FixedDialog so the user cannot resize it. If the user resized the form, the program would need to worry about drawing on an area that can change size, and that would be more work so I skipped it.
The code also sets the form's MinimizeBox and MaximizeBox properties to false so the user cannot minimize and maximize the form, respectively. The form's border style is FixedDialog, so these properties make me wonder, "What part of, 'do not allow the user to resize the form,' don't you understand?"
In this program, if the user minimizes the form, then it has width and height zero. That makes a later calculation will pass a negative value into the Random object's Next method and that crashes the program. Removing the MinimizeBox prevents that.
If the user maximizes the form, then the Bitmap (described shortly) doesn't fill the entire form so it is tiled. That's kind of interesting, but it isn't what I had in ind and it seems to noticeably hurt performance, so I prevent that, also.
The code also sets the form's DoubleBuffered property to true. That tells the form to draw its graphics in a secondary piece of memory and only display it when the drawing is complete. This is important for programs that draw a lot of graphics very quickly. If you don't set this property to true, the program flickers wildly. (Comment out that statement to see. It's pretty annoying.)
You can set the form's StartPosition property in the code, but by the time the Load event handler executes, the form has already been positioned, so that has no effect. If you want to change the form's startup position, you must do it at design time.
Next, the program creates a Bitmap to fit the form's client area. It also creates an associated Graphics object on which to draw. Finally, it sets the form's background image to the Bitmap so it will display anything that the program draws on the Bitmap (via the Graphics object).
At design time, I added a Timer that executes the following Tick event handler every 100 milliseconds. (Ten times per second).
private Random Rand = new Random();
private void tmrMakeRectangle_Tick(object sender, EventArgs e)
{
int x = Rand.Next(ClientSize.Width - 10);
int y = Rand.Next(ClientSize.Height - 10);
int width = Rand.Next(ClientSize.Width - x);
int height = Rand.Next(ClientSize.Height - y);
Color color = Color.FromArgb(128,
255 * Rand.Next(2),
255 * Rand.Next(2),
255 * Rand.Next(2));
using (Brush brush = new SolidBrush(color))
{
Gr.FillRectangle(brush, x, y, width, height);
}
Refresh();
}
The Rand object is declared at the class level so it is created only once and then every call to the event handler uses the same object. That is important. If the event handler created its own Random object, then that object would use the system time to initialize itself. If the event handler executes quickly enough, then some of its executions would use the same time to initialize the object so they would generate the same "random" numbers. that would mean the program would waste time generating the same rectangles multiple times.
This program doesn't run fast enough to generate too many duplicate rectangles if you create Random objects in that way, but it's better to use a single Random object if multiple methods will be generating random numbers very quickly. That avoid possible duplication and saves a little time creating, initializing, and destroying the objects.
The Tick event handler uses the Random object to pick X and Y coordinates for a rectangle's upper left corner. It leaves some space to the right and blow the possible X and Y coordinates so there is room for the rectangle to have a non-zero width and height.
The code then generates a random width and height and a random color. Each of the color's red, green, and blue components is either 0 or 255. That means the possible colors include:
- Black (all 0)
- White (all 255)
- The primary colors red, green, and blue (one component is 255 and the others are 0)
- The secondary colors yellow, cyan, and fuchsia (two components are 255 and one is 0)
The color's alpha (opacity) component is 128, so the color is semi-transparent and rectangles behind other rectangles show through.
After generating the random color, the program fills the random rectangle with it. The form already displays the bitmap Bm as its background image, so the code simply refreshes the form to display the result.
The only other piece to the program is the following KeyDown event handler.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
if (e.KeyCode == Keys.Escape) Gr.Clear(BackColor);
}
If you press Escape, this event handler clears the form's background so the drawing starts over.
Download the example and experiment with it. You might try making it draw ellipses instead of rectangles. Or try changing the way the random colors are generated. The program is amazingly simple but produces an interesting result.
Download the example to experiment with it and to see additional details.
|