5,276,156 members and growing! (19,589 online)
Email Password   helpLost your password?
Multimedia » GDI+ » General     Intermediate License: The Code Project Open License (CPOL)

Drawing and Editing Lines with GDI+

By Butch.er

Here's the code to implement a basic graphic user interface to paint, and then edit, lines on a PictureBox.
C#.NET 1.0, .NET 1.1, WinXP, Windows, .NET, GDI+, VS, VS.NET2003, Dev

Posted: 20 Oct 2004
Updated: 20 Oct 2004
Views: 95,179
Announcements
Want a new Job?



Search    
Advanced Search
Sitemap
27 votes for this Article.
Popularity: 5.60 Rating: 3.91 out of 5
5 votes, 18.5%
1
0 votes, 0.0%
2
0 votes, 0.0%
3
6 votes, 22.2%
4
16 votes, 59.3%
5

Sample Image - lineditor.jpg

Introduction

My first article! I hope that this code will help someone... I searched through the web and I found many developers (like me) looking for a way to implement line drawing/editing, that seems to be a thing very hard to implement, due to C# limitations in this topic... GDI+ doesn't seem to come in help very much, and I decided to make a solution by myself, that seems to work pretty fine :D. Here it is.

Once Upon a Time...

I started thinking about a Line Custom Control, but the result was very ugly, due to problems about transparency and Z-order (you cannot select a control that's under another one)... I then realized that the line itself had to be written directly to the PictureBox in order to avoid these problems, and the PictureBox.Image must be rewritten every time...

When the DrawLinebutton has been clicked, two red markers are placed in the PictureBox and a line is drawn. The two markers are actually two custom controls, inherited from UserControl, but they simply are a red square (that can be personalized, a cross, a circle, etc,), with no code inside. At the marker control creation, I attach three mouse events (MouseDown, MouseMove, MouseUp) in order to allow user to drag them around the PictureBox. Each time a marker is moved, all the lines (and the background image too) are redrawn. Very simple, isn't it?

Let's see some code...

private struct Line
{
    public MarkControl mark1;
    public MarkControl mark2;
    public int Width;
}

This object represents a line drawn on the PictureBox. It contains information about the two markers (their position, property Center) and the line width (editable through right mouse buttons). Each line drawn is added to an array of Lines; each time the image is redrawn, all the lines are redrawn using this info.

//Redraws all the lines and the background too

private void Redraw() 
{
    if(bmpBack!=null)
        image.Image = (Bitmap)bmpBack.Clone();
    else
    {
        image.Image = new Bitmap(image.Width,image.Height);
        Graphics.FromImage(image.Image).Clear(Color.White);
    }

    foreach(Line l in Lines)
    {
        DrawLine(l);
    }
    image.Refresh(); 
}

And this is the DrawLine function:

//Simply draws a line

private void DrawLine(Line line)
{
    Graphics g = null;

    g = Graphics.FromImage(image.Image);
    g.DrawLine(new Pen(Color.Black,(float)line.Width), 
               line.mark1.Center.X,line.mark1.Center.Y, 
               line.mark2.Center.X,line.mark2.Center.Y); 
    g.Dispose();
}

Amazing, it works! But there is a problem... When drawing lines on a big surface, like a desktop background, the program runs very slow, because the image is too heavy to be reloaded all the time... Then? I wrote a new Redraw(), that redraws all the lines in the same way, but refreshes only the region of the image that has been modified, through the Invalidate(Region region) method of the PictureBox... This trick code has to be a little enhanced, but it works very fine for now! If someone has a better idea, please tell me! Here's the code:

//Redraws all the lines and a part of the background

private void Redraw(Line line, Point p)
{
    Graphics.FromImage(image.Image).DrawImage(bmpBack,0,0, 
                       image.Image.Width, image.Image.Height);
    foreach(Line l in Lines)
    {
        DrawLine(l);
    }
    Region r = getRegionByLine(line,p);
    image.Invalidate(r);
    image.Update();
}

//Returns the region to update

private Region getRegionByLine(Line l, Point p)
{
    GraphicsPath gp = new GraphicsPath();
    gp.AddPolygon(new Point[]{l.mark1.Center,l.mark2.Center,p,l.mark1.Center});

    RectangleF rf = gp.GetBounds();
    gp.Dispose();

    rf.Inflate(100f,100f);

    return new Region(rf);
}

Line l is the line that has been moved, p is the Point where the marker has been moved... I calculate the region getting the triangle from the line and the point, then getting a rectangle that contains it, and then inflating it for a better result...

Lines Only?

This project can be modified as well, for other geometric figures like Circles, Ellipses, Rectangles, Polygons, and so on! Add more markers and use them as geometric points!

The End

Yeah, that's all folks ;) I hope that this article will help someone as other Code Project articles have helped me in my work everyday. Please send me feedbacks or/and advice! butch.er@tin.it.

Ciao!

License

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

About the Author

Butch.er



Occupation: Software Developer (Senior)
Location: Italy Italy

Other popular GDI+ articles:

Article Top
Sign Up to vote for this article
You must Sign In to use this message board.
FAQ FAQ Noise ToleranceSearch Search Messages 
 Layout  Per page   
 Msgs 1 to 25 of 38 (Total in Forum: 38) (Refresh)FirstPrevNext
Subject  Author Date 
GeneralText Wraping in MarkControlmemberrizwaanbutt20:06 31 Dec '07  
GeneralRe: Text Wraping in MarkControlmemberButch.er0:57 14 Feb '08  
QuestionProblem with: Picturebox size Mode & Marksmemberxupi0:59 12 Jul '07  
AnswerRe: Problem with: Picturebox size Mode & MarksmemberButch.er6:28 12 Jul '07  
QuestionRe: Problem with: Picturebox size Mode & Marksmemberxupi8:00 12 Jul '07  
QuestionNeed more Helpmemberrizwaanbutt22:14 22 May '07  
QuestionNeed your help to make it more fastermemberrizwaanbutt21:22 13 May '07  
AnswerRe: Need your help to make it more fastermemberButch.er0:30 14 May '07  
QuestionRe: Need your help to make it more fastermemberrizwaanbutt20:09 17 May '07  
QuestionRe: Need your help to make it more fastermemberjunzhi_li6:12 22 Jul '07  
GeneralResizable graphic areamemberGrusumZA0:26 13 Feb '07  
GeneralRe: Resizable graphic areamemberButch.er0:43 13 Feb '07  
GeneralRe: Resizable graphic areamemberGrusumZA0:59 13 Feb '07  
GeneralRe: Resizable graphic areamemberGrusumZA20:51 13 Feb '07  
GeneralI do not think so, it is not as good as it tismembernn81372:35 19 Nov '06  
QuestionRe: I do not think so, it is not as good as it tismemberButch.er22:41 27 Nov '06  
GeneralCoolmembermindtalk18:49 18 Oct '06  
QuestionRe: CoolmemberButch.er6:12 29 Nov '06  
QuestionProblems with new operator and pointersmemberFriendOfAsherah21:38 9 Oct '06  
AnswerRe: Problems with new operator and pointersmemberButch.er5:41 10 Oct '06  
AnswerRe: Problems with new operator and pointersmemberFriendOfAsherah11:09 11 Oct '06  
GeneralBrilliant! Thanks so much!!memberBFENGINEERING12:55 6 Oct '06  
JokeRe: Brilliant! Thanks so much!!memberButch.er5:11 10 Oct '06  
QuestionIncluding an erasermemberBroli14:20 6 May '06  
AnswerRe: Including an erasermemberButch.er0:21 11 Oct '06  

General General    News News    Question Question    Answer Answer    Joke Joke