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.