Click here to Skip to main content
11,928,605 members (50,167 online)
Click here to Skip to main content
Add your own
alternative version


215 bookmarked

Simple Vector Shapes

, 9 Jun 2009 CPOL
Rate this:
Please Sign up or sign in to vote.
A 2D vector shapes and RTFcontrol editor
Screenshot - vectshapes1.jpg


Hello. This is my 3rd article, after this one and this one. I propose a simple 2D vector graphic editor. It manages simple graphic objects like rectangles, lines and ellipses, other than images and RTF text. It shows most of the capabilities of GDI+, such as color transparency, pen style, start/end line cap and so on. All of the images shown in this article have been realized with the tool I propose.

Using the Code

Screenshot - vectshapes2.jpg

VectShape is the UserControl used to show and manipulate the objects. It contains the mouse event logic and the "extended" double buffer logic for rendering. It exposes a big set of methods. These methods are used mainly by toolBox, which is the control used to manipulate the shapes. Shapes is a collection of Ele. Ele is the base class for all of the objects: rectangles, boxText, Lines, Ellipses and imageBoxes. RichForm2 is the form used to edit RTF text. It's a simple form with a rich text box and a tool strip. Go to here for a better example of an RTF editor.


When searching The Code Project for GDI+, you'll find many good articles that explain what GDI+ is and the basis of drawing in .NET. In this article, I do not address these basic problems. An in-depth article on GDI+ can be found here.

Add Controls to Your Own Form

Simply put the controls vectShaper and toolBox into your form. Then link toolBox to vectShaper in the form (i.e. Form1) constructor:

public Form1()

    // added for linking toolbox to vectshapes

Now you're ready to start drawing some shapes.

Points of Interest

Drawing Objects: Extending Double Buffer

You can find many in-depth articles about Double Buffering (DB) on The Code Project. With the following 2 images, I will demonstrate how double buffering works. The idea of DB is to make the drawing on a memory bitmap buffer and then draw the buffer over the control.

Screenshot - vectshapes3.jpg Screenshot - vectshapes4.jpg

In this project, I extended the double buffer with two memory buffers. One is for drawing static objects and one is for storing dynamic/moving objects. See the next image:

Screenshot - vectshapes5.jpg
  1. backBuffG=Graphics.fromimage(backBuff)
  2. draws static objects over backBuffG
  3. buffG=Graphics.fromimage(buff)
  4. draws bitmap backBuffG over buffG
  5. draws moving objects over buffG
  6. ctrG=ctr.CreateGraphics()
  7. draws bitmap buffG over ctrG

backBuff is declared outside of the control redraw method. By STATIC objects, I mean all objects that we know aren't going to be moved/added/deleted/updated. In this kind of application, all of the objects that are not selected are static objects. Steps 1 and 2 are done only when we update the static objects. So, we don't redraw static objects in the paint method, but only the bitmap that "contains" them (Step 4).

Screenshot - vectshapes7.jpg

In this example, the blue objects are static. The selected objects -- the green selection rectangle and the handle rectangle -- are all dynamic/moving objects. So when I add/remove/update an object, such as in the MouseUp event of the control, I redraw the control including Steps 1 and 2. When I move a selected object -- i.e. in the MouseMove event or in the OnPaint event of the control -- I do not need to perform Steps 1 and 2. The static objects are drawn because I stored them in backBuff.

Rendering RichTextBox (RTF) on a Graphic Object

Another interesting point in this project is the rendering of the RTF contained in a rich text box. The Graphics.DrawString method lets you do something like that, but with a significant limitation. You can specify only one font, color or dimension in the same string. So, it does not draw truly RTF text. I was interested in rendering RTF text, so I Googled it and found this. It explains how to print the RTF contained in a rich text box control. The article contains the code for creating RichTextBoxPrintCtrl and demonstrates how to use it:

private static extern IntPtr SendMessage(IntPtr hWnd, int msg, 
    IntPtr wp, IntPtr lp);

// I extended the RichTextBoxPrintCtrl code by adding a Draw method:

public int Draw(int charFrom, int charTo, Graphics g, 
    int x, int y, int x1, int y1, double conversion)
    //Calculate the area to render and print
    RECT rectToPrint;
    rectToPrint.Top =(int)(y * conversion);
    rectToPrint.Bottom = (int)(y1 * conversion);
    rectToPrint.Left = (int)(x * conversion);
    rectToPrint.Right = (int)(decimal)(x1 * conversion);

    //Calculate the size of the page
    RECT rectPage;
    rectPage.Top = (int)(y * conversion);
    rectPage.Bottom = (int)(y1 * conversion);
    rectPage.Left = (int)(x * conversion);
    rectPage.Right =  (int)(x1 * conversion);
    IntPtr hdc = g.GetHdc();

    FORMATRANGE fmtRange;
    fmtRange.chrg.cpMax = charTo;//Indicate character from to character to 
    fmtRange.chrg.cpMin = charFrom;
    fmtRange.hdc = hdc;          //Use the same DC for measuring & rendering
    fmtRange.hdcTarget = hdc;    //Point at printer hDC
    fmtRange.rc = rectToPrint;   //Indicate the area on page to print
    fmtRange.rcPage = rectPage;  //Indicate size of page

    IntPtr res = IntPtr.Zero;

    IntPtr wparam = IntPtr.Zero;
    wparam = new IntPtr(1);

    //Get the pointer to the FORMATRANGE structure in memory
    IntPtr lparam = IntPtr.Zero;
    lparam = Marshal.AllocCoTaskMem(Marshal.SizeOf(fmtRange));
    Marshal.StructureToPtr(fmtRange, lparam, false);

    //Send the rendered data for printing 
    res = SendMessage(Handle, EM_FORMATRANGE, wparam, lparam);

    //Free the block of memory allocated

    //Release the device context handle obtained by a previous call
    //Return last + 1 character printer
    return res.ToInt32();

After that, there was a problem. The background color of the control RichetextBox was also rendered, while I was interested rendering only the text. So I found this, which explains how to make a control transparent:

//START : make this control trasparent
[DllImport("kernel32.dll", CharSet = CharSet.Auto)]
static extern IntPtr LoadLibrary(string lpFileName);

protected override CreateParams CreateParams
        CreateParams prams = base.CreateParams;
        if (LoadLibrary("msftedit.dll") != IntPtr.Zero)
            prams.ExStyle |= 0x020; // transparent
            prams.ClassName = "RICHEDIT50W";
           return prams;
// END

Et voilà. At this point, we have all we need to render real RTF text on a graphic object. I called it BoxTesto; it is a box (rectangle) with a start and an end point and all of the properties derived from the Ele class. In addition, it has an RTF property that contains a string with the RTF text. When I draw a BoxTesto, I create a "transparent" RichTextBoxPrintCtrl control and assign RichTextBoxPrintCtrl.rtf with BoxTesto.rtf. Then I call RichTextBoxPrintCtrl.Draw.


I choose to implement the undo/redo as a double-linked list. Each item on the list contains a reference to the object of interest, an old copy of the object and a new copy of the object. In the next image, I present the undo/redo list in blue and the modified objects in black.

Screenshot - vectshapes6.jpg

Every time I change an object, I store an element in the undo/redo list. When I need to undo an action, I copy the OLD object properties over the interested object properties. Then I go back one element in the undo/redo list. When I need to redo an action, I go forward one element in the undo/redo list. Then I copy the NEW object properties over the object referenced by the element. The "lazy" way: in my old project, I implemented undo/redo like a circular array where the objects stored were the entire collection of graphic objects. That was an easy and fast solution, but too memory-hungry.

Drawing Images (Rotation/Transparency)

Screenshot - vectshapes8.jpg

Now I focus on image drawing (method Draw, class ImgBox, file Shapes.cs) to show how to implement image rotation and transparency:

//get the back color from the first pixel (UP-LEFT)
Color backColor = this.img.GetPixel(0, 0); 
//Create a tmp Bitmap and a graphic object
// the dimension of the tmp bitmap must permit the rotation of img
int dim = 
    (int)System.Math.Sqrt(img.Width * img.Width + img.Height * img.Height);
Bitmap curBitmap = new Bitmap(dim, dim);
Graphics curG = Graphics.FromImage(curBitmap);

if (this.Rotation >
    // activate the rotation on the graphic obj
    Matrix X = new Matrix();
    X.RotateAt(this.Rotation, new PointF(curBitmap.Width / 2, 
        curBitmap.Height / 2));
    curG.Transform = X;        
// I draw img over the tmp bitmap 
curG.DrawImage(img, (dim - img.Width) / 2, (dim - img.Height) / 2, 
    img.Width, img.Height);

if (this.Trasparent)
    curBitmap.MakeTransparent(backColor); // here I perform trasparency

// I draw the tmp bitmap on canvas
g.DrawImage(curBitmap, new Rectangle(this.X + dx, 
    this.Y + dy, this.X1 - this.X, this.Y1 - this.Y));


  • 15 June, 2007 -- Original version posted

Update 1

  1. Added ZoomIN/ZoomOut
  2. Added right mouse click canvas movement
  3. Added image rotation
  4. Added Transparent Image property

Update 2

  1. Added obj --> Group and obj --> deGroup functions
  2. Added a rotation handle for object rotation
    Screenshot - vectshapes9.jpg
  3. Added File--> Save selected objects / File --> Load objects
  4. Created Help page

Update 3

  1. Added Gradient Line Fill Color, i.e. draw a shape, fill it and then set the UseGradientLineColor property to true
  2. Added Group Resize / Rotation and Zoom Management
  3. Can show a Group like a GraphicPath, i.e. select some Lines and then select them, group them and set the graphPath property to true
  4. Added example *.shape files. Load them from File --> Load
    Screenshot - vectshapes10.jpg

Update 4

  1. Added Free Hand Pen Tool
  2. Added Obj-->Poly--> X/Y Mirror
  3. Added Obj-->Poly--> Merge
  4. Added Obj-->Poly--> Extract Points

Update 5

  1. Added Draw Graph Tool


This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


About the Author

andrea contoli
Software Developer
Italy Italy
No Biography provided

You may also be interested in...

Comments and Discussions

Questionany idea about making block diagrams Pin
hasan baghal26-Jun-15 16:34
memberhasan baghal26-Jun-15 16:34 
Questionkeep shapes in memory Pin
hasan baghal26-Jun-15 14:43
memberhasan baghal26-Jun-15 14:43 
GeneralThanks you so much!!!!! Pin
memberRIVASBROTHERS11-May-15 7:49 
QuestionScroll bar left right , top down in shape form Pin
hasan baghal24-Mar-15 23:15
memberhasan baghal24-Mar-15 23:15 
AnswerRe: Scroll bar left right , top down in shape form Pin
andrea contoli25-Mar-15 0:05
memberandrea contoli25-Mar-15 0:05 version Pin
Member 1148686716-Mar-15 3:14
memberMember 1148686716-Mar-15 3:14 
AnswerRe: version Pin
andrea contoli16-Mar-15 4:36
memberandrea contoli16-Mar-15 4:36 
Questionhow about zoom operation? Pin
yxsylyh16-Oct-14 22:06
memberyxsylyh16-Oct-14 22:06 
QuestionHi! There is a bug Pin
Member 101085112-Jul-14 10:42
memberMember 101085112-Jul-14 10:42 
AnswerRe: Hi! There is a bug Pin
acontoli30-Jul-14 23:08
memberacontoli30-Jul-14 23:08 
Questionhow about draw an active gif , marching ant or running pipes Pin
Marksion2-Apr-14 23:55
memberMarksion2-Apr-14 23:55 
QuestionTag property Pin
Trial227-Aug-13 4:53
memberTrial227-Aug-13 4:53 
AnswerRe: Tag property Pin
acontoli27-Aug-13 21:31
memberacontoli27-Aug-13 21:31 
GeneralRe: Tag property Pin
Trial228-Aug-13 5:31
memberTrial228-Aug-13 5:31 
QuestionGuideline or Magnetic effects... Pin
klrodel4-Jun-13 23:29
memberklrodel4-Jun-13 23:29 
GeneralMy vote of 5 Pin
avoliogab1-Feb-13 9:07
memberavoliogab1-Feb-13 9:07 
Generalmy vote of 5 Pin
Member 822540725-Nov-12 4:56
memberMember 822540725-Nov-12 4:56 
GeneralMy vote of 5 Pin
Member 822540725-Nov-12 4:54
memberMember 822540725-Nov-12 4:54 
GeneralMy vote of 5 Pin
nekimiro30-Jun-12 3:50
membernekimiro30-Jun-12 3:50 
QuestionExcellent ! Pin
Member 81679031-Jun-12 5:42
memberMember 81679031-Jun-12 5:42 
QuestionHow i can get line (or other) object inside the mousover method? Pin
Member 864892327-Apr-12 8:58
memberMember 864892327-Apr-12 8:58 
AnswerRe: How i can get line (or other) object inside the mousover method? Pin
acontoli1-May-12 21:35
memberacontoli1-May-12 21:35 
GeneralMy vote of 5 Pin
manoj kumar choubey22-Feb-12 0:43
membermanoj kumar choubey22-Feb-12 0:43 
GeneralMy vote of 5 Pin
Nazmi Altun13-Oct-11 0:25
memberNazmi Altun13-Oct-11 0:25 
GeneralImplementing Left,Center and Right Text allignment Pin
Member 774292525-Jun-11 21:37
memberMember 774292525-Jun-11 21:37 
GeneralSave /Save As /New Pin
Member 774292525-Jun-11 20:10
memberMember 774292525-Jun-11 20:10 
GeneralSave/Save As/New Pin
Member 774292525-Jun-11 20:10
memberMember 774292525-Jun-11 20:10 
GeneralMini SlideShow !! Pin
kienhv_8716-Jun-10 0:18
memberkienhv_8716-Jun-10 0:18 
GeneralRe: Mini SlideShow !! Pin
acontoli16-Jun-10 1:19
memberacontoli16-Jun-10 1:19 
GeneralRe: Mini SlideShow !! [modified] Pin
kienhv_8716-Jun-10 16:13
memberkienhv_8716-Jun-10 16:13 
QuestionWhat time can test the links? Pin
hudawei12-Apr-10 6:41
memberhudawei12-Apr-10 6:41 
AnswerRe: What time can test the links? Pin
acontoli14-Apr-10 22:14
memberacontoli14-Apr-10 22:14 
QuestionOpen a exist image Pin
sarahconnor1-Apr-10 20:24
membersarahconnor1-Apr-10 20:24 
AnswerRe: Open a exist image Pin
acontoli1-Apr-10 21:13
memberacontoli1-Apr-10 21:13 
GeneralRe: Open a exist image Pin
sarahconnor1-Apr-10 22:38
membersarahconnor1-Apr-10 22:38 
GeneralThis article did helped me a lot Pin
Damonpeng23-Mar-10 9:08
memberDamonpeng23-Mar-10 9:08 
GeneralExport Graphic in High Res Pin
chingyen19-Jan-10 14:38
memberchingyen19-Jan-10 14:38 
QuestionThanks! - Background image - Additonal external element Pin
erkan islamovic29-Oct-09 5:58
membererkan islamovic29-Oct-09 5:58 
AnswerRe: Thanks! - Background image - Additonal external element Pin
acontoli29-Oct-09 6:10
memberacontoli29-Oct-09 6:10 
GeneralRe: Thanks! - Background image - Additonal external element Pin
erkan islamovic29-Oct-09 23:28
membererkan islamovic29-Oct-09 23:28 
GeneralIs it possible to draw free hand non-vector Pin
harbz18-Sep-09 23:07
memberharbz18-Sep-09 23:07 
GeneralRe: Is it possible to draw free hand non-vector Pin
acontoli29-Oct-09 6:11
memberacontoli29-Oct-09 6:11 
GeneralReally Appreciate you !!! Pin
Anand Ranjan Pandey5-Feb-09 22:51
memberAnand Ranjan Pandey5-Feb-09 22:51 
Generala lot of flickering Pin
Ilango.M16-Sep-08 5:32
memberIlango.M16-Sep-08 5:32 
GeneralRe: a lot of flickering Pin
acontoli17-Sep-08 21:48
memberacontoli17-Sep-08 21:48 
GeneralRe: a lot of flickering Pin
canderse9-Oct-08 1:55
membercanderse9-Oct-08 1:55 
Generalopen source project on codeplex Pin
canderse23-Jul-08 23:06
membercanderse23-Jul-08 23:06 
GeneralGREAT STUFF !!! ( but why are the demo versions and the compiled versions different?) Pin
RichardTrainer20-Jul-08 0:49
memberRichardTrainer20-Jul-08 0:49 
GeneralRe: GREAT STUFF !!! ( but why are the demo versions and the compiled versions different?) Pin
acontoli20-Jul-08 22:09
memberacontoli20-Jul-08 22:09 
QuestionI want to Save to *Bmp ?? Pin
trantranh8-Jul-08 21:36
membertrantranh8-Jul-08 21:36 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.

| Advertise | Privacy | Terms of Use | Mobile
Web04 | 2.8.151126.1 | Last Updated 9 Jun 2009
Article Copyright 2007 by andrea contoli
Everything else Copyright © CodeProject, 1999-2015
Layout: fixed | fluid