Creating Your Own Drawing Application with Visual Basic .NET, Part 1

Because I'm a Visual Basic 6 veteran, I've always wanted to be able to write a proper Drawing Application. Without the use of the Windows API, Visual Basic 6's graphics capabilities was a bit too limited for my taste. GDI+ came to my rescue. This article series will introduce you to most of the features of GDI+ and how easy GDI+ actually is in a hands-on manner.

Designing the Interface

First, start with the Main Window. It probably comes as no surprise that this will be an MDI application. The reason for this is that you can have more than one drawing open at any given time. To add this MDI form to your application, Select Project, Add Windows Form.... Name this Form frmMDICanvas. The next thing you need to do with frmMDICanvas is to set the IsMdiContainer property to True.

Add a MainMenu component to this From; name the menu CMMFile. Include the following Menu items:

  • &File and leave the default name
  • &New and name this item mnuFNew

Voilà! Your first form is designed!

At a bare minimum, every graphics application has a ToolBox (to select tools and other various options, such as Colors and Drawing styles) and a Canvas on which to draw. With the included sample program, I have included the following options in the ToolBox:

  • Shapes
    • Circle
    • Square
    • Triangle
  • Drawing Options
    • Outlined
    • Filled
  • Color Selector
  • Eraser
  • Pencil Tool

In Design mode, the Toolbox looks like the following picture:

The Canvas in the included sample consists of an empty PictureBox, to be drawn on, and a Button to clear the drawing. In Design mode, the Canvas looks like the following picture:

As you can see, the design of this application is very basic at this stage.

Get Building!

  1. Start Visual Studio .NET.
  2. When prompted for a new Project name, enter Canvas for the Project's name.
  3. When the first Form appears, open its Properties Window, and set the following properties:
    • Name: frmCanvas
    • Text: Computer Canvas
    • WindowState: Maximized
  4. Add a PictureBox control to frmCanvas by double-clicking on it in the Toolbox. Set the following properties for the PictureBox:
    • Name: picCDraw
    • BackColor: White
    • Cursor: Cross
    • Dock: Fill
  5. Add a Button to the PictureBox in the same way you did the PictureBox. Set the following properties for the Button control:
    • Name: butCClear
    • Anchor: Bottom, Left
    • BackColor: White
    • FlatStyle: Flat
    • Image: Set the Button's Image Property to any picture that would describe the button's use. If you choose not to include a picture for the button, set the Button's Text Property to Clear.
    • Size: 75, 32. Width: 75 Height: 32
  6. Add a ToolTip control to the Designer, and set the following property for the ToolTip:
    • Name: tipCanvas

That's it! Your canvas has been designed. It doesn't look like much at this stage, but you will see further improvements to your canvas during the course of this article series. What you need now is a Toolbox for your drawing program.

Creating the Toolbox

To create your Toolbox, follow these steps:

  1. From the Project menu, select Add Windows Form... to add a new form to your project. When the Add New Item dialog box appears, type the following name for the new form: frmTools.vb.
  2. When the new form appears in the Designer Window, set the following properties for frmTools:
    • Name: frmTools
    • BackColor: White
    • ControlBox: False
    • FormBorderStyle: FixedToolWindow
    • ShowInTaskBar: False
    • Size: 112, 312 Width: 112 Height: 312
    • StartPosition: Manual
    • Text: Tools
    • TopMost: True
  3. Add a Button to your frmTools, and set the following properties:
    • Name: butCCircle
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Location: 16, 8 X: 16, Y: 8
    • Size: 75, 23 Width: 75, Height: 23
    • Text: Circle
  4. Add a Button to your frmTools, and set the following properties:
    • Name: butCSquare
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Location: 16, 8 X: 16, Y: 8
    • Size: 75, 23 Width: 75 Height: 23
    • Text: Square
  5. Add a Button to your frmTools, and set the following properties:
    • Name: butCTriangle
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Location: 16, 8 X: 16, Y: 8
    • Size: 75, 23 Width: 75 Height: 23
    • Text: Triangle
  6. Add a Button to your frmTools, and set the following properties:
    • Name: butCFillColor
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Image: Set the Button's Image Property to any picture, that would describe the button's use. If you choose not to include a picture for the button, set the Button's Text Property to Fill.
    • Note: You may need to adjust the Width property if you choose to include Text instead of an Image.
    • Location: 16, 208 X: 16 Y: 208
    • Size: 32, 32 Width: 32 Height: 32
  7. Add a Button to your frmTools, and set the following properties:
    • Name: butCPencil
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Image: Set the Button's Image Property to any picture that would describe the button's use. If you choose not to include a picture for the button, set the Button's Text Property to Pencil.
    • Note: You may need to adjust the Width property if you choose to include Text instead of an Image.
    • Location: 56, 208 X: 56, Y: 208
    • Size: 32, 32 Width: 32 Height: 32
  8. Add a Button to your frmTools, and set the following properties:
    • Name: butCColor
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Image: Set the Button's Image Property to any picture that would describe the button's use. If you choose not to include a picture for the button, set the Button's Text Property to Color.
    • Note: You may need to adjust the Width property if you choose to include Text instead of an Image.
    • Location: 16, 248 X: 16 Y: 248
    • Size: 32, 32 Width: 32 Height: 32
  9. Add a Button to your frmTools, and set the following properties:
    • Name: butCEraser
    • BackColor: White
    • FlatStyle: Popup
    • Font:Arial, Arial, 8.25pt
    • ForeColor: Black
    • Image: Set the Button's Image Property to any picture that would describe the button's use. If you choose not to include a picture for the button, set the Button's Text Property to Eraser.
    • Note: You may need to adjust the Width property if you choose to include Text instead of an Image.
    • Location: 56, 248 X: 56 Y: 248
    • Size: 32, 32 Width: 32 Height: 32
  10. Add a ToolTip control to the Designer, and set the following property for the ToolTip:
    • Name: tipCanvas

Now that you have finished the design of your first drawing application in .NET, you can start coding. Before you do that, however, let me explain what the whole goal of the above forms and their controls are.

Functions of the Various Controls

frmTools

Object Description
frmTools Provides a holding place for all drawing tools
butCCircle Draws a circle
butCSquare Draws a square
butCTriangle Draws a triangle
butCFillColor Draws a filled shape
butCPencil Draws freehand
butCColor Opens the color selector
butCEraser Erases drawings
tipCanvas Provides tooltips for the various tools

frmCanvas

Object Description
frmCanvas Provides the drawing canvas
picCDraw PictureBox to draw onto
butCClear Clears the entire drawing
tipCanvas Provides tooltips

Now, get coding!

Creating Your Own Drawing Application with Visual Basic .NET, Part 1

Now that you have the design in place, you can finally get started coding. I will demonstrate all the necessary code, step by step. All you have to do is follow along and enjoy, and, most importantly, learn how easy GDI+ is!

Because you are dealing with two forms (one for the tools, one for the canvas), you will need to add a Module to your project. You need to do this because you are going to declare Global variables that are variables that are used with multiple forms. To add a Module to your project, follow these easy steps:

  1. Select the Project menu.
  2. Select Add Module. A box similar to the following picture appears:
  3. [AddModule.png]

  4. Type in a descriptive name: modCanvas, for example.
  5. Click OK.

In modCanvas, type in the following:

Public blnDrawClicked As Boolean        'Is The Pencil Tool Clicked?
Public blnSquareClicked As Boolean      'Is The Square Tool Clicked?
Public blnTriangleClicked As Boolean    'Is The Triangle Tool Clicked?
Public blnCircleClicked As Boolean      'Is The Circle Tool Clicked?
Public blnEraserClicked As Boolean      'Is The Eraser Tool Clicked?
Public blnFillClicked As Boolean        'Is The Fill Tool Clicked?
Public blnColorClicked As Boolean       'Is The Color Tool Clicked?
Public cColor As Color                  'Selected Color To Draw With

As you have probably noticed, the variables above will be used to determine which tool has been selected. The variables will return a True value when the particular tool has been selected. Boolean variables can be either True or False. The last variable that is declared inside modCanvas is named cColor; it will be used to hold the currently selected color.

frmTools

The first event you are going to create is the butCCircle_Click event. To add coding to the click event of the Circle button, simply double-click on it in the designer, and then type the following code:

Private Sub butCCircle_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCCircle.Click
'Set All Boolean Flags Of Tools Click To False, Except For The
'Current One: Circle

blnTriangleClicked = False
blnSquareClicked   = False
blnDrawClicked     = False
blnEraserClicked   = False
blnCircleClicked   = True
'Refresh/Repaint The Buttons, To Indicate Current Selection State

butCCircle.Refresh()
butCSquare.Refresh()
butCTriangle.Refresh()
End Sub

Follow the same procedure as above to add code to the butCSquare_Click, butCTriangle_Click, butCPencil_Click, and the butCEraser_Click events. Your code for these four functions should look similar to the following code segments:

Private Sub butCSquare_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCSquare.Click
'Set All Boolean Flags Of Tools Click To False, Except For The
'Current One: Square

blnCircleClicked   = False
blnTriangleClicked = False
blnDrawClicked     = False
blnEraserClicked   = False
blnSquareClicked   = True
'Refresh/Repaint The Buttons, To Indicate Current Selection State

butCCircle.Refresh()
butCSquare.Refresh()
butCTriangle.Refresh()
End Sub

Private Sub butCTriangle_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCTriangle.Click
'Set All Boolean Flags Of Tools Click To False, Except For The
'Current One: Triangle

blnCircleClicked   = False
blnSquareClicked   = False
blnDrawClicked     = False
blnEraserClicked   = False
blnTriangleClicked = True
'Refresh/Repaint The Buttons, To Indicate Current Selection State

butCCircle.Refresh()
butCSquare.Refresh()
butCTriangle.Refresh()
End Sub

Private Sub butCPencil_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCPencil.Click
'Set All Boolean Flags Of Tools Click To False, Except For The
'Current One: Pencil

blnCircleClicked   = False
blnTriangleClicked = False
blnSquareClicked   = False
blnDrawClicked     = True
'Refresh/Repaint The Buttons, To Indicate Current Selection State

butCCircle.Refresh()
butCSquare.Refresh()
butCTriangle.Refresh()
End Sub

Private Sub butCEraser_Click(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles butCEraser.Click
'Set All Boolean Flags Of Tools Click To False, Except For The
'Current One: Eraser

blnCircleClicked   = False
blnTriangleClicked = False
blnSquareClicked   = False
blnDrawClicked     = False
blnEraserClicked   = True
'Refresh/Repaint The Buttons, To Indicate Current Selection State

butCCircle.Refresh()
butCSquare.Refresh()
butCTriangle.Refresh()
End Sub

What you have accomplished with the preceding code is mostly just setting the global variables (declared in modCanvas) to True or False, depending on which button is selected. You also have called the Refresh methods of the buttons to repaint their appearance once the button is clicked. Speaking of button appearance, experiment a little with the button controls. With the next section of code, you are going to make the Circle button circular, the Square button square shaped, and the Triangle button will end up looking like a triangular-shaped button. To change the shapes of the button controls, you create a GraphicsPath Object, add a shape to the GraphicsPath object, and set the Button's Region = to the GraphicsPath object. Add the following code in the buttons' respective Paint events:

Private Sub butCCircle_Paint(ByVal sender As Object, _
   ByVal e As System.Windows.Forms.PaintEventArgs) _
   Handles butCCircle.Paint
'Declare A GraphicsPath Object, Which Is Used To Draw The Shape Of
'The Button

Dim CirclePath As System.Drawing.Drawing2D.GraphicsPath =
   New System.Drawing.Drawing2D.GraphicsPath
'Create A 60 x 60 Circle Path

CirclePath.AddEllipse(New Rectangle(0, 0, 60, 60))
'Size Of The Button

butCCircle.Size = New System.Drawing.Size(60, 60)
If blnCircleClicked Then
   'If The Button Is Selected To Draw, Change The Color

   butCCircle.BackColor = Color.DeepSkyBlue
Else

   'If The Button Is Not Selected To Draw With, Change Back To
   'Original Color

   butCCircle.BackColor = Color.Aquamarine
End If
'Create The Circular Shaped Button, Based On The Graphics Path

butCCircle.Region = New Region(CirclePath)
'Release All Resources Owned By The Graphics Path Object

CirclePath.Dispose()
End Sub

Private Sub butCSquare_Paint(ByVal sender As System.Object, _
   ByVal e As System.Windows.Forms.PaintEventArgs) _
   Handles butCSquare.Paint
'Declare A GraphicsPath Object, Which Is Used To Draw The Shape Of
'The Button

Dim SquarePath As System.Drawing.Drawing2D.GraphicsPath =
   New System.Drawing.Drawing2D.GraphicsPath
'Create A 60 x 60 Square Path

SquarePath.AddRectangle(New Rectangle(0, 0, 60, 60))
'Size Of The Button

butCSquare.Size = New System.Drawing.Size(60, 60)
If blnSquareClicked Then
   'If The Button Is Selected To Draw, Change The Color

   butCSquare.BackColor = Color.DeepSkyBlue
Else

   'If The Button Is Not Selected To Draw With, Change Back To
   'Original Color

   butCSquare.BackColor = Color.Aquamarine
End If
'Create The Square Shaped Button, Based On The Graphics Path

butCSquare.Region = New Region(SquarePath)
'Release All Resources Owned By The Graphics Path Object

SquarePath.Dispose()
End Sub

Private Sub butCTriangle_Paint(ByVal sender As Object, _
   ByVal e As System.Windows.Forms.PaintEventArgs) _
   Handles butCTriangle.Paint
'Declare A GraphicsPath Object, Which Is Used To Draw The Shape Of
'The Button

Dim TrianglePath As System.Drawing.Drawing2D.GraphicsPath =
   New System.Drawing.Drawing2D.GraphicsPath
'Create A Triangle Path, With A Total Width And Height Of 60, The
'Lines From The Bottom Meet At 30 At The Top

Dim pTPoints As Point() = { _
   New Point(30, 0), _
   New Point(60, 60), _
   New Point(0, 60)}
'Add The Point Array Object To The GraphicsPath Object. The Point
'Array Is Needed To Create The Three Interconnected Points

TrianglePath.AddLines(pTPoints)
'Size Of The Button

butCTriangle.Size = New System.Drawing.Size(60, 60)
If blnTriangleClicked Then
   'If The Button Is Selected To Draw, Change The Color

   butCTriangle.BackColor = Color.DeepSkyBlue
Else

   'If The Button Is Not Selected To Draw With, Change Back To
   'Original Color

   butCTriangle.BackColor = Color.Aquamarine
End If
'Create The Triangular Shaped Button, Based On The Graphics Path

butCTriangle.Region = New Region(TrianglePath)
'Release All Resources Owned By The Graphics Path Object

TrianglePath.Dispose()
End Sub

The code above will create a circle-shaped button, a square-shaped button, and a triangular-shaped button. All these buttons will also change colors once they are clicked, and then change back to the original color once a different shape is selected.

The FillColor Button has two options:

  1. Outlined Color
  2. Filled Color

What I did in the next code segment was to declare a Modular variable that keeps track of how many times the FillColor button is clicked. When the variable has a value of 1, you will have filled colors. If the variable's value is 2, you will return to Outlined color mode. I have also changed the Images on this button to give the user a visible clue to what option is currently selected. You can omit the Images if you want to. Have a closer look:

Declare the sFillClicked variable in the Declarations section of frmTools:

Private sFillClicked As Short 'Keeps Track Of How Many Times The
                              'Fill Tool Is Clicked

Add the butCFillColor_Click event procedure:

Private Sub butCFillColor_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCFillColor.Click
'How Many Times Is This Tool Clicked ?
sFillClicked = sFillClicked + 1

'If This Tool Is Clicked Once ...
If sFillClicked = 1 Then
   'Load A Different Picture (Change State)
   butCFillColor.Image = Image.FromFile("PaintBucket.png")

   'Display A Different ToolTip, To Indicate State/Tool Change
   tipCanvas.SetToolTip(butCFillColor, "Return to Outline Color")

   'Fill Is Clicked, Fill The Objects Based On blnFillClicked
   blnFillClicked = True
Else
   'Fill Is Not Clicked Anymore, Return To Original Button/Tool State
   sFillClicked = 0
   blnFillClicked = False
   butCFillColor.Image = Image.FromFile("PaintBrush.png")
   tipCanvas.SetToolTip(butCFillColor, "Draw A Filled Shape")
End If

End Sub

All this talk about shapes and Outlined or Filled colors, and you haven't got colors yet! You can quickly fix that problem. The following code handles the butCColor event. What I did here was to declare a new ColorDialog object, which will be used to select colors to draw with. If a color is selected, the selected color is stored in the cColor variable; if no color has been selected, cColor will default to black.

Private Sub butCColor_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCColor.Click
blnColorClicked = True
'Create A New ColorDialog Object

Dim CColorD As New ColorDialog

'Settings For CColorD

'Open Full Dialog Box
CColorD.FullOpen = True
'Do Not Display Help Button On TitleBar
CColorD.ShowHelp = False

'Display All Available Colors
CColorD.AnyColor = True

'If OK Is Selected On The Color DialogBox
If (CColorD.ShowDialog() = System.Windows.Forms.DialogResult.OK) Then
   'Change The Selection Color To The User Specified Color.
   cColor = CColorD.Color
Else
   'Cancel Was Clicked, return To default
   cColor = System.Drawing.Color.Black
End If

End Sub

All you need to do now with frmTools is to create and set the various Tooltips for all the various Tools in our Toolbox. You accomplish this in the Form_Load event:

Private Sub frmTools_Load(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles MyBase.Load
'Set ToolTips Of All Tools, To Inform User What Each Tool Does
tipCanvas.SetToolTip(butCCircle,    "Draw A Circle")
tipCanvas.SetToolTip(butCSquare,    "Draw A Square")
tipCanvas.SetToolTip(butCTriangle,  "Draw A Triangle")
tipCanvas.SetToolTip(butCFillColor, "Draw A Filled Shape")
tipCanvas.SetToolTip(butCPencil,    "Draw Free Hand")
tipCanvas.SetToolTip(butCColor,     "Select A Color")
tipCanvas.SetToolTip(butCEraser,    "Eraser")

End Sub

Now, when a user hover his/her mouse over one of the tools in the Toolbox, they will get a tooltip explaining the Tool's purpose.

If you thought creating the Toolbox was fun, you're going to love what you do with frmCanvas!

Creating Your Own Drawing Application with Visual Basic .NET, Part 1

frmCanvas, as you know by now, will be your physical drawing area for the tool the user selected from the Toolbox. All the drawings will take place in the PictureBox's MouseUp event, meaning, when the user releases the mouse button, the object will be drawn. I also made use of the MouseDown event of the PictureBox, to keep track of the starting points of the particular drawing. The drawing will be drawn from the Starting points to the Ending points as will be specified in the MouseUp event. The picCDraw_MouseMove event will be used when the user has selected the Pencil tool to draw freehand shapes, and with the Eraser tool, so that the drawing will be erased as the user move his mouse.

The first event I will cover here is the frmCanvas_Load event.

Private Sub frmCanvas_Load(ByVal sender As Object, _
   ByVal e As System.EventArgs) Handles MyBase.Load
'Set ToolTip Property For Clear Tool

tipCanvas.SetToolTip(butCClear, "Clear Canvas")
End Sub

To actually start drawing, you need a couple of declarations. Here, I am declaring the starting and ending X and Y positions for your drawings. sStartX and sStartY will be set to a value once the mouse button is pressed down. sEndX and sEndY will be set to values at the psoition where the Mouse Button is released.

'Declare Starting Points For Drawn Objects

Private sStartX As Short
Private sStartY As Short
'Declare Ending points For Drawn Objects

Private sEndX As Short
Private sEndY As Short

The following two declarations will be used to establish whether the Drawing or Erasing tools are selected:

'Is The User Drawing Free Hand?
Private blnDrawing As Boolean

'Is The User Erasing?
Private blnErasing As Boolean

With the next two declarations, I create a Bitmap object and a Graphics object. The Bitmap object has a Width Of 1100 And Height Of 800. The Drawn Shapes will become part of this Image Object. The Graphics object will be used to draw onto.

'Create A New Image Object With Width Of 1500 And Height Of 1200.
'The Drawn Shapes Will Become Part Of This Image Object
Private bImage As New Bitmap(1500, 1200)
'Declare The Graphics Object To Draw Onto

Private gCanvas As Graphics = Graphics.FromImage(bImage)

As mentioned earlier, the MouseDown event of the PictureBox initializes the Starting X and Y values of your drawing. This event also checks to see whether the user is currently drawing Freehand with the Pencil tool, or if the user is currently erasing.

Private Sub picCDraw_MouseDown(ByVal sender As System.Object, _
   ByVal e As System.Windows.Forms.MouseEventArgs) _
   Handles picCDraw.MouseDown
'Determine Whether Or Not The Pencil (Free Hand) Tool Has Been Clicked

If blnDrawClicked Then
   blnDrawing = True
End If
'Determine Whether Or Not The Eraser Tool Has Been Clicked

If blnEraserClicked Then
   blnErasing = True
End If
'Initialise Starting Points Of Shape, Once Mouse Button Is Pressed Down

sStartX = e.X
sStartY = e.Y
End Sub

The MouseUp event is where all the drawing of the shapes actually takes place.

Private Sub picCDraw_MouseUp(ByVal sender As System.Object, _
   ByVal e As System.Windows.Forms.MouseEventArgs) _
   Handles picCDraw.MouseUp
'Create And Initialise Pens To Draw The Particular Outline Shapes
'with a Width of 3 and a black color
Dim pCirclePen   As New Pen(Color.Black, 3)
Dim pSquarePen   As New Pen(Color.Black, 3)
Dim pTrianglePen As New Pen(Color.Black, 3)

'Create And Initialise Brushes To Fill The Particular Shapes With Black
Dim sbCircleBrush   As New SolidBrush(Color.Black)
Dim sbSquareBrush   As New SolidBrush(Color.Black)
Dim sbTriangleBrush As New SolidBrush(Color.Black)

'Initialise Ending Points Of Shape, Once Mouse Button Is Released
sEndX = e.X
sEndY = e.Y

'If The Pencil (Free Hand) Tools Is NOT Selected, In Other Words,
'A Shape Tool Is Selected
If Not blnDrawing Then
   'Set The Images Drawn Thus Far In The Picture Box = To The
   'In-Memory Image Object
   Me.picCDraw.Image = bImage

   'A Color Has Not Been Selected, Revert To Default Black Color
   If Not blnColorClicked Then
      cColor = Color.Black
   Else

      'A Color Has Been Selected, Use Selected Color To Draw With
      cColor = cColor
   End If

   'Determine If The Circle Tool Has Been Clicked
   If blnCircleClicked Then
      'Yes, It Has Been Clicked, Set The Pen's Color To Selected Color
      pCirclePen.Color = cColor

      'Draw The Circle With The Current Starting, And Ending Values.
      'We must subtract the Starting values from the Ending values,
      'to make sure the shape's Starting and ending values are
      'precisely those where you started drawing, and where you
      'ended drawing.
      gCanvas.DrawEllipse(pCirclePen, sStartX, sStartY, _
                          sEndX - sStartX, sEndY - sStartY)

      'Was The Fill Tool Clicked
      If blnFillClicked Then
         'Yes, Set The Brush Color To The Selected Color
         sbCircleBrush.Color = cColor

         'Fill The Shape Being Drawn
         gCanvas.FillEllipse(sbCircleBrush, sStartX, sStartY, _
                             sEndX - sStartX, sEndY - sStartY)
      End If
   End If

'Determine If The Square Tool Has Been Clicked
If blnSquareClicked Then
   'Yes, It Has Been Clicked, Set The Pen's Color To Selected Color
   pSquarePen.Color = cColor

   'Draw The Square With The Current Starting, And Ending Values
   'Get Exact Starting X values
   Dim SquareX      As Integer      = Math.Min(sStartX, sEndX)
   'Get Exact Starting Y values
   Dim SquareY      As Integer      = Math.Min(sStartY, sEndY)
   'Subtract End from Start
   Dim SquareWidth  As Integer      = Math.Abs(sStartX - sEndX)
   'Subtract End from Start
   Dim SquareHeight As Integer      = Math.Abs(sStartY - sEndY)

   'Draw precise Square with correct starting and ending coordinates
   gCanvas.DrawRectangle(pSquarePen, SquareX, SquareY, SquareWidth, _
                         SquareHeight)

   'Was The Fill Tool Clicked
   If blnFillClicked Then
      'Yes, Set The Brush Color To The Selected Color
      sbSquareBrush.Color = cColor

      'Fill The Shape Being Drawn
      gCanvas.FillRectangle(sbSquareBrush, SquareX, SquareY, _
                            SquareWidth, SquareHeight)
   End If

End If

'Determine If The Triangle Tool Has Been Clicked
If blnTriangleClicked Then
   'Yes, It Has Been Clicked, Set The Pen's Color To Selected Color
   pTrianglePen.Color = cColor

   'Create The Triangle Based On User's Mouse Coordinates + 150,
   'To Make The Triangle Display A Bit "Fatter"
   gCanvas.DrawLine(pTrianglePen, sStartX, sStartY, sEndX, sEndY)
   gCanvas.DrawLine(pTrianglePen, sEndX, sEndY, Me.MousePosition.X, _
                    Me.MousePosition.Y + 150)
   gCanvas.DrawLine(pTrianglePen, sStartX, sStartY, _
                    Me.MousePosition.X, _
                    Me.MousePosition.Y + 150)

   'Was The Fill Tool Clicked
   If blnFillClicked Then
      'Use A Point Array, In Order To Be Able To Use The
      'FillPolygon Method - To Fill The Triangle
      Dim pTPoints As Point() = { _
      New Point(sStartX, sStartY), _
      New Point(sEndX, sEndY), _
      New Point(Me.MousePosition.X, Me.MousePosition.Y + 150)}

      'Yes, Set The Brush Color To The Selected Color
      sbTriangleBrush.Color = cColor

      'Fill The Shape Being Drawn
      gCanvas.FillPolygon(sbTriangleBrush, pTPoints)
   End If
End If
End If

'If The User Is Not Erasing, Refresh The Picturebox's Display
If Not blnErasing Then
   picCDraw.Refresh()
End If

'Dispose Of All Pens
pCirclePen.Dispose()
pSquarePen.Dispose()
pTrianglePen.Dispose()

'Dispose Of All Brushes
sbCircleBrush.Dispose()
sbSquareBrush.Dispose()
sbTriangleBrush.Dispose()

'Set The Drawing And Erasing Flags To False, Because The Mouse
'Button Is Realease - We're Not drawing/Erasing ANymore
blnDrawing = False
blnErasing = False
End Sub

The PictureBox's MouseMove event is used to keep track of the mouse position while Drawing Freehand or erasing.

Private Sub picCDraw_MouseMove(ByVal sender As System.Object, _
   ByVal e As System.Windows.Forms.MouseEventArgs) _
   Handles picCDraw.MouseMove

'Declare A Eraser Pen, Used To Erase Parts Of  Drawing.
Dim pEraserPen As New Pen(Color.White, 15)

'Declare A Drawing Pen, Used To Draw Free Hand, Once Pencil Tool
'Is Selected.
Dim pDrawingPen As New Pen(Color.Black, 3)

'Are We Drawing?
If blnDrawing Then
   'Yes We Are, Set The Pen Color To Selected Color
   pDrawingPen.Color = cColor

   'Draw The Free Hand Lines
   gCanvas.DrawLine(pDrawingPen, sStartX, sStartY, e.X, e.Y)

   'Set New Starting Points For Next Line. New Starting Points Are
   'The End Points Of Previous Line
   sStartX = e.X
   sStartY = e.Y

   'Set The Images Drawn Thus Far In The Picture Box = To The
   'In-Memory Image Object
   Me.picCDraw.Image = bImage
End If

'Are We Erasing?
If blnErasing Then
   'Yes We Are,    'Draw The Eraser Lines Lines
   gCanvas.DrawLine(pEraserPen, sStartX, sStartY, e.X, e.Y)

   'Set New Starting Points For Next Line. New Starting Points Are
   'The End Points Of Previous Line
   sStartX = e.X
   sStartY = e.Y

   'Set The Images Drawn Thus Far In The Picture Box = To The
   'In-Memory Image Object
   Me.picCDraw.Image = bImage
End If

'Dispose Of Both Pens
pEraserPen.Dispose()
pDrawingPen.Dispose()
End Sub

All you need to do now is add code to the Clear button to Clear the canvas, so that the user can start drawing again.

Private Sub butCClear_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles butCClear.Click
'Clear The Canvas and set the Canvas color to white
gCanvas.Clear(Color.White)

'Refresh The Picturebox's Display
picCDraw.Refresh()
End Sub

frmMDICanvas

All that you still need to do in your project is to load and display the forms. You will quickly do this inside the Load event of frmMDICanvas. You also need to Load new instances of your Drawing form when the New menu item is clicked.

Private Sub frmMDICanvas_Load(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles MyBase.Load
   Dim FTools As New frmTools

   Dim FCanvas As New frmCanvas

   FTools.MdiParent = Me
   FCanvas.MdiParent = Me
   FTools.Show()
   FCanvas.Show()

   'Set Appriate Location For Tools Window. x = 1, y = Middle Of
   'The Screen Height
   FTools.Location = New Point(1, (Me.Height - FTools.Height) / 2)
   FTools.BringToFront()
End Sub

Private Sub mnuFNew_Click(ByVal sender As System.Object, _
   ByVal e As System.EventArgs) Handles mnuFNew.Click
   Dim FCanvas As New frmCanvas

   FCanvas.MdiParent = Me

   FCanvas.Show()
End Sub

Before you build and run your very first drawing application, you need to make sure that the VB .NET IDE knows which form to start with. You have to change it because, when you first started building the design of frmCanvas, you changed the name of the default form created. To change the Default startup form, follow these steps:

  • On the Main menu, select Project.
  • Select Canvas Properties.
  • Select General under Common Properties.
  • On the Startup Object drop down list control, select frmMDICanvas.
  • Click OK.

Now, Build and Run Your Program!

Feel free to hone your drawing skills. As you can see, I'm not much of an artist! After drawing some random shapes, my canvas ended up looking like the following picture.

[Finished.jpg]

Conclusion

I hope that you have enjoyed creating a basic framework for your Drawing Application. In the next article in this series, you will continue to build your Graphics Application. Improvements that you can expect in Part 2 are:

  • Showing a marquee while drawing
  • Filling the drawn objects


About the Author

Hannes du Preez

Hannes du Preez is a Microsoft MVP for Visual Basic. He is a trainer at a South African-based company. He is the co-founder of hmsmp.co.za, a community for South African developers.

Downloads

Comments

  • There are no comments yet. Be the first to comment!

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

Top White Papers and Webcasts

  • Live Event Date: October 29, 2014 @ 11:00 a.m. ET / 8:00 a.m. PT Are you interested in building a cognitive application using the power of IBM Watson? Need a platform that provides speed and ease for rapidly deploying this application? Join Chris Madison, Watson Solution Architect, as he walks through the process of building a Watson powered application on IBM Bluemix. Chris will talk about the new Watson Services just released on IBM bluemix, but more importantly he will do a step by step cognitive …

  • Live Event Date: November 20, 2014 @ 2:00 p.m. ET / 11:00 a.m. PT Are you wanting to target two or more platforms such as iOS, Android, and/or Windows? You are not alone. 90% of enterprises today are targeting two or more platforms. Attend this eSeminar to discover how mobile app developers can rely on one IDE to create applications across platforms and approaches (web, native, and/or hybrid), saving time, money, and effort and introducing apps to market faster. You'll learn the trade-offs for gaining long …

Most Popular Programming Stories

More for Developers

Latest Developer Headlines

RSS Feeds