| Simple Painting Program in VB.NET Posted by: Xav in Untagged on Jul 22, 2008 |
Code samples are in Visual Basic.NET, but directly apply to C# as well. Replace "Me" with "this" if you are using C#.
Hi again. Let me tell you all about .NET - no, OK, I've already bored you. Now we'll look at something so cool - the System.Drawing namespace, and particularly, GDI+.
The code within Windows that handles drawing things is known as the Graphical Device Interface, or GDI for short. This draws everything, such as text, shapes and lines. Windows generates drawing commands to the GDI, which processes it, but the GDI also manages the applications' drawing instructions as well. It interacts directly with the graphics drivers and so on, which means there's some good news - we don't have to worry about them. This is referred to as Device Independance - we tell the GDI what to draw, and it draws it for us.
Of course, .NET makes it easy for us.
The .NET Magic
As I say, anything you can do, .NET can do better. And this is especially true with drawing, as you will see.
We use the Graphics object to draw things. We always tie a Graphics object to another object, either a control or an image. I think it is best to illustrate this by putting it into our program.
1. Drag the form out a bit, to make it big enough to draw properly on.
2.Double click the form to access its load event. Type the following:

We are using a Graphics object called gfx. You cannot instantiate a Graphics object by using the New keyword - you must do it by referencing another object. Here, the Me object represents the current form. We wish to draw on to the form, so therefore we must reference it. By calling its CreateGraphics() function, we return a Graphics object, which can be set to the instance of the gfx object.
Now, we haven't yet created our gfx object yet, so:
3. Add the following to the top o the code file, just under the "Public Class" bit, but before the "Private Sub" bits:

The variable has been declared as Private so that the form's subroutines can access it. By default VB does this anyway when you insert it in this certain place, but it's good to specify the scope anyway.
At your disposal
You must, must dispose of your Graphics objects. Remember, they hold references to other objects, so the Garbage Collector cannot release their resources until they are disposed of. We do this by calling the Dispose() method, which takes no parameters, and simply allows the object to be destroyed.
4. Open the drop-down list at the top of the window that contains the events (the upper left one) and choose FormClosed. A new subroutine will be created in the code file, which will be made as an event handler to the FormClosed event.
5. Type the following code to dispose of the object:

Painting with the Mouse
Now for the fun part. We want to be able to draw on the form when we hold down the left mouse button and move around, just like a normal painting program. Therefore, we need the form's MouseMove event:
6. Select the event drop-down list again, and this time choose the MouseMove event. Another procedure should be created, tied to the MouseMove event of the form.
Whenever the mouse is moved over the form, the MouseMove event is called. However, we only want to paint if the left mouse button is held down:
7. Add the following code to the MouseMove event handler:

The "e" object is of type MouseMoveEventArgs. It contains information about the current event - in this case, the mouse. The Button property tells us which button was pressed. It is read-only.
We use a simple conditional statement to test whether the left button is pressed down using <>. If it isn't, we exit out of the code, because we don't want to draw unless the button is held down.
Now we just have to draw! We are going to draw a small circle where the mouse is, and if we move the mouse around, we can draw lines and shapes:
8. Add the following code to the MouseMove event handler, following the Exit Sub bit:

This is pretty cool. We always need a rectangle, regardless of what we want to draw. A Rectangle object simply holds four values - an X coordinate, a Y coordinate, a width and a height. In short, it tells us where and how big to draw a shape. The circle, known to .NET as an ellipse, will have those dimensions, that we will now specify:
9. Add the following code to the MouseMove event handler:

Confusing? We use a With statement to save us typing the word "rect" all the time. The code above specifies that the ellipse (circle) will be 2 pixels wide and high (1 pixel radius). If we just drew the ellipse using the current coordinates of the mouse, the circle would appear off-centre. This is because the coordinates specify the top-left hand corner of the circle, not the centre. Therefore, we offset by one, which is half the width and height of the circle. This draws it in the right place.
Now, we just have to actually draw the ellipse:
9. Add the following code to the MouseMove event handler:

You can change the System.Drawing.Pen to suit your preferred colour. Even better, make it so that the user can select a colour from a ColorDialog, and perhaps a width as well. To draw a square instead, use DrawRectangle() with the same parameters.
Running the Project
That's it! Save and run the project (press F5). Move the mouse over the form, hold down the left mouse button, and paint! Have fun!
Note: If you move the mouse quickly, there will be gaps inbetween the circles. This is because the MouseEvent cannot fire quickly enough.
Hi again. Let me tell you all about .NET - no, OK, I've already bored you. Now we'll look at something so cool - the System.Drawing namespace, and particularly, GDI+.
The code within Windows that handles drawing things is known as the Graphical Device Interface, or GDI for short. This draws everything, such as text, shapes and lines. Windows generates drawing commands to the GDI, which processes it, but the GDI also manages the applications' drawing instructions as well. It interacts directly with the graphics drivers and so on, which means there's some good news - we don't have to worry about them. This is referred to as Device Independance - we tell the GDI what to draw, and it draws it for us.
Of course, .NET makes it easy for us.
The .NET Magic
As I say, anything you can do, .NET can do better. And this is especially true with drawing, as you will see.
We use the Graphics object to draw things. We always tie a Graphics object to another object, either a control or an image. I think it is best to illustrate this by putting it into our program.
1. Drag the form out a bit, to make it big enough to draw properly on.
2.Double click the form to access its load event. Type the following:

- gfx = Me.CreateGraphics()
gfx = Me.CreateGraphics()
We are using a Graphics object called gfx. You cannot instantiate a Graphics object by using the New keyword - you must do it by referencing another object. Here, the Me object represents the current form. We wish to draw on to the form, so therefore we must reference it. By calling its CreateGraphics() function, we return a Graphics object, which can be set to the instance of the gfx object.
Now, we haven't yet created our gfx object yet, so:
3. Add the following to the top o the code file, just under the "Public Class" bit, but before the "Private Sub" bits:

- Private gfx As Graphics
Private gfx As Graphics
The variable has been declared as Private so that the form's subroutines can access it. By default VB does this anyway when you insert it in this certain place, but it's good to specify the scope anyway.
At your disposal
You must, must dispose of your Graphics objects. Remember, they hold references to other objects, so the Garbage Collector cannot release their resources until they are disposed of. We do this by calling the Dispose() method, which takes no parameters, and simply allows the object to be destroyed.
4. Open the drop-down list at the top of the window that contains the events (the upper left one) and choose FormClosed. A new subroutine will be created in the code file, which will be made as an event handler to the FormClosed event.
5. Type the following code to dispose of the object:

- gfx.Dispose()
gfx.Dispose()
Painting with the Mouse
Now for the fun part. We want to be able to draw on the form when we hold down the left mouse button and move around, just like a normal painting program. Therefore, we need the form's MouseMove event:
6. Select the event drop-down list again, and this time choose the MouseMove event. Another procedure should be created, tied to the MouseMove event of the form.
Whenever the mouse is moved over the form, the MouseMove event is called. However, we only want to paint if the left mouse button is held down:
7. Add the following code to the MouseMove event handler:

- If e.Button <> Windows.Forms.MouseButtons.Left Then Exit Sub
If e.Button <> Windows.Forms.MouseButtons.Left Then Exit Sub
The "e" object is of type MouseMoveEventArgs. It contains information about the current event - in this case, the mouse. The Button property tells us which button was pressed. It is read-only.
We use a simple conditional statement to test whether the left button is pressed down using <>. If it isn't, we exit out of the code, because we don't want to draw unless the button is held down.
Now we just have to draw! We are going to draw a small circle where the mouse is, and if we move the mouse around, we can draw lines and shapes:
8. Add the following code to the MouseMove event handler, following the Exit Sub bit:

- Dim rect As Rectangle
Dim rect As Rectangle
This is pretty cool. We always need a rectangle, regardless of what we want to draw. A Rectangle object simply holds four values - an X coordinate, a Y coordinate, a width and a height. In short, it tells us where and how big to draw a shape. The circle, known to .NET as an ellipse, will have those dimensions, that we will now specify:
9. Add the following code to the MouseMove event handler:

- With rect
- .X = e.X - 1
- .Y - e.Y - 1
- .Width = 2
- .Height = 2
- End With
With rect
.X = e.X - 1
.Y - e.Y - 1
.Width = 2
.Height = 2
End With
.X = e.X - 1
.Y - e.Y - 1
.Width = 2
.Height = 2
End With
Confusing? We use a With statement to save us typing the word "rect" all the time. The code above specifies that the ellipse (circle) will be 2 pixels wide and high (1 pixel radius). If we just drew the ellipse using the current coordinates of the mouse, the circle would appear off-centre. This is because the coordinates specify the top-left hand corner of the circle, not the centre. Therefore, we offset by one, which is half the width and height of the circle. This draws it in the right place.
Now, we just have to actually draw the ellipse:
9. Add the following code to the MouseMove event handler:

- gfx.DrawEllipse(System.Drawing.Pens.Red, rect)
gfx.DrawEllipse(System.Drawing.Pens.Red, rect)
You can change the System.Drawing.Pen to suit your preferred colour. Even better, make it so that the user can select a colour from a ColorDialog, and perhaps a width as well. To draw a square instead, use DrawRectangle() with the same parameters.
Running the Project
That's it! Save and run the project (press F5). Move the mouse over the form, hold down the left mouse button, and paint! Have fun!
Note: If you move the mouse quickly, there will be gaps inbetween the circles. This is because the MouseEvent cannot fire quickly enough.