Introduction
In the first installment of this article series, “Creating a Shape Editor in .NET,” we created the framework for our drawing application. With this installment, you will create the canvas to draw on and create the shapes. The functionality already exists for the shapes to be resized and dragged about.
There is a tonne of work, so let’s get started!
Create the line-snapping ability:
C#
public class lnSnap
{
public lnSnap(int X1, int Y1, int X2, int Y2,
Color LineColor)
{
this.X1 = X1;
this.Y1 = Y1;
this.X2 = X2;
this.Y2 = Y2;
this.Color = LineColor;
}
public int X1 { get; set; }
public int Y1 { get; set; }
public int X2 { get; set; }
public int Y2 { get; set; }
public Color Color { get; set; }
public void Draw(Graphics g)
{
using (var p = new Pen(this.Color))
{
g.DrawLine(p, this.X1, this.Y1, this.X2, this.Y2);
}
}
}
VB.NET
Imports System.Drawing
Public Class lnSnap
Public Sub New(ByVal X1 As Integer, ByVal Y1 As Integer, _
ByVal X2 As Integer, ByVal Y2 As Integer, _
ByVal LineColor As Color)
Me.X1 = X1
Me.Y1 = Y1
Me.X2 = X2
Me.Y2 = Y2
Me.Color = LineColor
End Sub
Public Property X1 As Integer
Public Property Y1 As Integer
Public Property X2 As Integer
Public Property Y2 As Integer
Public Property Color As Color
Public Sub Draw(ByVal g As Graphics)
Using p = New Pen(Me.Color)
g.DrawLine(p, Me.X1, Me.Y1, Me.X2, Me.Y2)
End Using
End Sub
End Class
The lnSpan class gives us the ability to show different colored snapping lines when we move the drawings into each other’s vicinity. Add the following code:
C#
public class shpCircle : shpShape
{
public shpCircle(Point loc) : base(loc)
{
}
public override string ShapeName()
{
return "Circle";
}
public override void Draw(Graphics g)
{
using (var b = new SolidBrush(this.BackColor))
{
g.FillEllipse(b, this.Bounds);
g.DrawEllipse(Pens.Black, this.Bounds);
}
}]
VB.NET
shpCircle.vb
Imports System.Drawing
Public Class shpCircle
Inherits shpShape
Public Sub New(ByVal loc As Point)
MyBase.New(loc)
End Sub
Public Overrides Function ShapeName() As String
Return "Circle"
End Function
Public Overrides Sub Draw(ByVal g As Graphics)
Using b = New SolidBrush(Me.BackColor)
g.FillEllipse(b, Me.Bounds)
g.DrawEllipse(Pens.Black, Me.Bounds)
End Using
End Sub
End Class
This class creates a circle by using the DrawEllipse and FillEllipse methods. You obviously could add more shapes in here such as squares, triangles, and other polygons, but I’ll add that functionality perhaps a bit later. Add the next class.
C#
public class shpColl : System.Collections.ObjectModel.Collection
<shpShape>
{
private readonly shpCanvas canvas;
public shpColl(shpCanvas c)
{
canvas = c;
}
public event EventHandler CollectionChanged;
protected virtual void OnCollectionChanged(EventArgs e)
{
if (CollectionChanged != null) this.CollectionChanged
(this, e);
}
private string FreeName(Type t)
{
if (t.IsSubclassOf(typeof(shpShape)))
{
var shapes = new List<shpShape>();
foreach (shpShape s in this)
{
if (t == s.GetType())
{
shapes.Add(s);
}
}
var ht = new Hashtable(shapes.Count);
foreach (shpShape s in shapes)
ht[s.Name] = null;
shpShape instance = (shpShape)Activator.CreateInstance
(t, new object[] { Point.Empty });
string defName = instance.ShapeName();
int i = 1;
while (ht.ContainsKey(defName + i))
i++;
return defName + i;
}
else
{
return String.Empty;
}
}
}
VB.NET
Imports System.Drawing
Public Class shpColl
Inherits System.Collections.ObjectModel.Collection(Of shpShape)
Private ReadOnly canvas As shpCanvas
Public Sub New(ByVal c As shpCanvas)
canvas = c
End Sub
Public Event CollectionChanged As EventHandler
Protected Overridable Sub OnCollectionChanged(ByVal e As _
EventArgs)
RaiseEvent CollectionChanged(Me, e)
End Sub
Private Function FreeName(ByVal t As Type) As String
If t.IsSubclassOf(GetType(shpShape)) Then
Dim shapes = New List(Of shpShape)()
For Each s As shpShape In Me
If t = s.[GetType]() Then
shapes.Add(s)
End If
Next
Dim ht = New Hashtable(shapes.Count)
For Each s As shpShape In shapes
ht(s.Name) = Nothing
Next
Dim instance As shpShape = CType(Activator. _
CreateInstance(t, New Object() {Point.Empty}), _
shpShape)
Dim defName As String = instance.ShapeName()
Dim i As Integer = 1
While ht.ContainsKey(defName & i)
i += 1
End While
Return defName & i
Else
Return String.Empty
End If
End Function
End Class
The aptly named shpColl class hosts a collection of shapes that have been drawn on the canvas. Now, speaking about the canvas…
Well, If I were to add the Canvas class’ code here in its entirety, it will take a very long time to read and use. I do not want you to just copy and paste the code and not understand it. That defeats the whole object of this article, all my articles, any other articles out there. Let me leave that task to a third and final part (which will be coming soon).
Conclusion
All we need now is a platform, or canvas, to draw our shapes on. This will be covered in the next and final installment. Until then, learn the code of this article, and the previous one. Experiment, toy and play with it, as that is how you learn.