Creating a Simple Drawing Application


Before discussing the UML class diagram editor project in detail, let's look at a much-simplified version of the project. In fact, this simple drawing application can draw one shape only: rectangles. Understanding this simple application will help you understand the project.

The application has two classes: the DrawArea class that extends System.Windows.Forms.Panel and the form. The draw area fills the whole client area of the form. To draw a rectangle, the user clicks on the draw area and drags the mouse along. The first click point is the top-left corner of the rectangle. The point where the user releases the mouse becomes the bottom-right corner of the rectangle. Because you cannot guarantee that the user will drag the mouse to the left and down when drawing a rectangle, the release point could be located left of the starting point. If this is the case, then you have a problem because the two constructors of the System.Drawing.Rectangle class require you to pass a Point object representing the upper-left corner of the rectangle or the coordinate of that point.

The solution to this problem is the DrawArea class's GetRectangleFromPoints method, which you can use to obtain a System.Drawing.Rectangle object. The two points passed to this method can be any points in the draw area. You will see the GetRectangleFromPoints method after looking at the DrawArea class.

The DrawArea class extends the System.Windows.Forms.Panel class (see Listing 4-6).

Listing 4-6: The DrawArea Class

start example
 Imports System.Drawing Imports System.Collections Imports System.Windows.Forms Public Class DrawArea : Inherits Panel   Private shapes As New ArrayList()   Private startPoint As Point   Public Sub New()     AddHandler Me.MouseDown, AddressOf me_MouseDown     AddHandler Me.MouseUp, AddressOf me_MouseUp   End Sub   Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)     Dim g As Graphics = e.Graphics     Dim shapeEnum As IEnumerator = shapes.GetEnumerator     Dim blackPen As Pen = Pens.Black     While shapeEnum.MoveNext       Dim rectangle As Rectangle = CType(shapeEnum.Current, Rectangle)       g.DrawRectangle(blackPen, rectangle)     End While   End Sub   Private Sub me_MouseDown(ByVal sender As System.Object, _     ByVal e As MouseEventArgs)     If e.Button = MouseButtons.Left Then       startPoint = New Point(e.X, e.Y)     End If   End Sub   Private Sub me_MouseUp(ByVal sender As System.Object, _     ByVal e As MouseEventArgs)     If e.Button = MouseButtons.Left Then       Dim endPoint As New Point(e.X, e.Y)       Dim r As Rectangle = GetRectangleFromPoints(startPoint, endPoint)       shapes.Add(r)       Me.Refresh()     End If   End Sub   Public Shared Function GetRectangleFromPoints(ByVal p1 As Point, _     ByVal p2 As Point) As Rectangle     Dim x1, x2, y1, y2 As Integer     If p1.X < p2.X Then       x1 = p1.X       x2 = p2.X     Else       x1 = p2.X       x2 = p1.X     End If     If p1.Y < p2.Y Then       y1 = p1.Y       y2 = p2.Y     Else       y1 = p2.Y       y2 = p1.Y     End If     ' x2 > x1 and y2 > y1     Return New Rectangle(x1, y1, x2 - x1, y2 - y1)   End Function End Class 
end example

Note

To compile the DrawArea class in Listing 4-6, use the following command from the directory in which the listing-04.06.vb file resides: vbc /t:library /r:System.dll,System.Windows.Forms.dll, System.Drawing.dll listing-04.06.vb (all on one line).

The DrawArea class has a private System.Collection.ArrayList object in which all Rectangle objects drawn are stored. The DrawArea class overrides the OnPaint method so that all rectangles can be redrawn whenever the Paint event triggers.

In the constructor, the DrawArea class wires the MouseDown event with the me_MouseDown event handler and the MouseUp event with the me_MouseUp event handler:

 AddHandler Me.MouseDown, AddressOf me_MouseDown AddHandler Me.MouseUp, AddressOf me_MouseUp 

The me_MouseDown event handler is called whenever the user clicks on the DrawArea object. The event handler is passed a MouseEventArgs object, from which you can obtain the Button object of the mouse and the coordinate of the click point (in the form of X and Y properties). What the me_MouseDown event does is check if the mouse button clicked was MouseButton.Left. If it was, it constructs a Point object containing the clicked point coordinate and assigns the Point object to the startPoint variable:

 If e.Button = MouseButtons.Left Then   startPoint = New Point(e.X, e.Y) End If 

The me_MouseUp event handler is invoked when the user releases the mouse button. It first checks if the mouse button released was MouseButtons.Left. If it was, it constructs a Point object containing the point at which the user released the mouse button and assigns it to the local variable endPoint.

 Dim endPoint As New Point(e.X, e.Y) 

It then passes both points to the GetRectangleFromPoints method to obtain a Rectangle object and add the Rectangle object to the shapes ArrayList:

 Dim r As Rectangle = GetRectangleFromPoints(startPoint, endPoint) shapes.Add(r) 

Finally, it calls the Refresh method to force the surface to be repainted:

 Me.Refresh() 

You need the GetRectangleFromPoints method because you cannot guarantee that the startPoint will be on the top-left of the end point. The GetRectangleFromPoints method checks the coordinate of the two points and creates new points, if necessary, so that the first point will have an x coordinate and a y coordinate whose values are less than the values of the x and y coordinates of the second point.

Then, it constructs a Rectangle object by passing the two new coordinates and returns the Rectangle object.

The form in the application adds a DrawArea object as its child control and sets its Dock property to DockStyle.Fill. It also changes the background color of the DrawArea object to white.

Listing 4-7 shows the form.

Listing 4-7: The Form

start example
 Imports System Imports System.Windows.Forms Imports System.Drawing Imports System.Drawing.Drawing2D Public Class Form1 : Inherits Form   Private drawArea As New DrawArea()   Public Sub New()     Me.ClientSize = New System.Drawing.Size(740, 585)     drawArea.Dock = DockStyle.Fill     Me.Controls.Add(drawArea)     drawArea.BackColor = Color.White   End Sub   <STAThread()> Shared Sub Main()     Dim f As New Form1()     Application.Run(f)   End Sub End Class 
end example

Note

To compile the form in Listing 4-7, use the following command from the directory in which the listing-04.07.vb file resides: vbc /t:winexe /r:System.dll,System.Windows.Forms.dll, System.Drawing.dll,listing-04.06.dll listing-04.07.vb (all on one line).

If you run the application, you can click and drag to draw a Rectangle object.

However, you probably notice one thing. When you drag your mouse, there is nothing to remind you of where the start point is. You also cannot see the size of the rectangle you are drawing.

To make it look more professional, you can add a feature so that you can see the rectangle you are drawing. The main thing you need to do is capture one more event: MouseMove.

To add the new feature, do the following steps to the DrawArea class:

  1. Add the movingEndPoint variable of type Point in the class declaration:

     Private movingEndPoint As Point 
  2. Wire the MouseMove event to the me_MouseMove event handler in the constructor. The new constructor will look like this:

     Public Sub New()    AddHandler Me.MouseDown, AddressOf me_MouseDown    AddHandler Me.MouseMove, AddressOf me_MouseMove    AddHandler Me.MouseUp, AddressOf me_MouseUp End Sub 
  3. Assign the movingEndPoint value to the startPoint every time the mouse is clicked. In the me_MouseDown event handler, add the line of code in bold:

     Private Sub me_MouseDown(ByVal sender As System.Object, _   ByVal e As MouseEventArgs)   If e.Button = MouseButtons.Left Then   startPoint = New Point(e.X, e.Y)   movingEndPoint = startPoint   End If End Sub 
  4. Add the me_MouseMove event handler to handle the MouseMove event. This event triggers when the user drags the mouse. You need to draw a temporary rectangle and remove the previous temporary rectangle. This is the me_MouseMove event handler:

     Private Sub me_MouseMove(ByVal sender As System.Object, _   ByVal e As MouseEventArgs)   If e.Button = MouseButtons.Left Then     Dim endPoint As New Point(e.X, e.Y)     Dim graphics As Graphics = Me.CreateGraphics     'remove the previous rectangle     graphics.DrawRectangle(Pens.White, _       GetRectangleFromPoints(startPoint, movingEndPoint))     movingEndPoint = endPoint     Me.Refresh()     'draw a temporary rectangle     graphics.DrawRectangle(Pens.Black, _       GetRectangleFromPoints(startPoint, movingEndPoint))   End If End Sub 

Listing 4-8 gives the updated DrawArea class. The Form1 class remains unchanged.

Listing 4-8: The DrawArea Class That Captures the MouseMove Event

start example
 Imports System.Drawing Imports System.Collections Imports System.Windows.Forms Public Class DrawArea : Inherits Panel   Private shapes As New ArrayList()   Private startPoint As Point   Private movingEndPoint As Point   Public Sub New()     AddHandler Me.MouseDown, AddressOf me_MouseDown     AddHandler Me.MouseMove, AddressOf me_MouseMove     AddHandler Me.MouseUp, AddressOf me_MouseUp   End Sub   Protected Overrides Sub OnPaint(ByVal e As PaintEventArgs)     Dim g As Graphics = e.Graphics     Dim shapeEnum As IEnumerator = shapes.GetEnumerator     Dim blackPen As Pen = Pens.Black     While shapeEnum.MoveNext       Dim rectangle As Rectangle = CType(shapeEnum.Current, Rectangle)       g.DrawRectangle(blackPen, rectangle)     End While   End Sub   Private Sub me_MouseDown(ByVal sender As System.Object, _     ByVal e As MouseEventArgs)     If e.Button = MouseButtons.Left Then       startPoint = New Point(e.X, e.Y)       movingEndPoint = startPoint     End If   End Sub   Private Sub me_MouseMove(ByVal sender As System.Object, _     ByVal e As MouseEventArgs)     If e.Button = MouseButtons.Left Then       Dim endPoint As New Point(e.X, e.Y)       Dim graphics As Graphics = Me.CreateGraphics       graphics.DrawRectangle(Pens.White, _         GetRectangleFromPoints(startPoint, movingEndPoint))       movingEndPoint = endPoint       Me.Refresh()       graphics.DrawRectangle(Pens.Black, _         GetRectangleFromPoints(startPoint, movingEndPoint))     End If   End Sub   Private Sub me_MouseUp(ByVal sender As System.Object, _     ByVal e As MouseEventArgs)     If e.Button = MouseButtons.Left Then       Dim endPoint As New Point(e.X, e.Y)       Dim r As Rectangle = GetRectangleFromPoints(startPoint, endPoint)       shapes.Add(r)       Me.Refresh()     End If   End Sub   Public Shared Function GetRectangleFromPoints(ByVal p1 As Point, _     ByVal p2 As Point) As Rectangle     Dim x1, x2, y1, y2 As Integer     If p1.X < p2.X Then       x1 = p1.X       x2 = p2.X     Else       x1 = p2.X       x2 = p1.X     End If     If p1.Y < p2.Y Then       y1 = p1.Y       y2 = p2.Y     Else       y1 = p2.Y       y2 = p1.Y     End If     ' x2 > x1 and y2 > y1     Return New Rectangle(x1, y1, x2 - x1, y2 - y1)   End Function End Class 
end example




Real World. NET Applications
Real-World .NET Applications
ISBN: 1590590821
EAN: 2147483647
Year: 2005
Pages: 82

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net