65.9K
CodeProject 正在变化。 阅读更多。
Home

使用 GDI+ 绘制和编辑线条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.82/5 (41投票s)

2004年10月21日

CPOL

3分钟阅读

viewsIcon

253168

downloadIcon

6881

这是一个实现基本图形用户界面,用于在 PictureBox 上绘制和编辑线条的代码。

Sample Image - lineditor.jpg

引言

我的第一篇文章! 我希望这段代码能帮助到别人... 我在网上搜索,发现许多开发者(像我一样)都在寻找实现线条绘制/编辑的方法,由于 C# 在这方面的限制,这似乎是一件非常难实现的事情... GDI+ 似乎并没有提供很大的帮助,所以我决定自己做一个解决方案,它看起来运行得相当好 :D。 就是它了。

很久以前...

我开始考虑创建一个 Line 自定义控件,但由于透明度和 Z 顺序的问题,结果非常糟糕(你不能选择一个在另一个控件下面的控件)... 然后我意识到线条本身必须直接写入 PictureBox,以避免这些问题,并且每次都必须重写 PictureBox.Image...

当点击 DrawLine 按钮后,两个红色标记放置在 PictureBox 中,并绘制一条线。 这两个标记实际上是两个自定义控件,继承自 UserControl,但它们只是一个红色正方形(可以个性化,一个十字,一个圆等),内部没有代码。 在标记控件创建时,我附加了三个鼠标事件(MouseDownMouseMoveMouseUp),以便允许用户在 PictureBox 周围拖动它们。 每次移动一个标记时,所有线条(以及背景图像)都会被重绘。 非常简单,不是吗?

让我们看看一些代码...

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

此对象表示在 PictureBox 上绘制的线条。 它包含关于两个标记(它们的位置,属性 Center)和线条宽度的信息(可以通过鼠标右键编辑)。 绘制的每条线都会添加到 Line 的数组中;每次重绘图像时,都会使用此信息重绘所有线条。

//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(); 
}

这是 DrawLine 函数

//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();
}

太棒了,它工作了! 但是有一个问题... 当在一个大的表面上绘制线条时,例如桌面背景,程序运行速度非常慢,因为图像太重,无法一直重新加载... 那么? 我编写了一个新的 Redraw(),它以相同的方式重绘所有线条,但刷新图像中已修改的区域,通过 PictureBoxInvalidate(Region region) 方法... 这个技巧代码需要稍微增强一下,但现在运行得很好! 如果有人有更好的想法,请告诉我! 这是代码

//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 是已被移动的线条,p 是标记已移动到的 Point... 我通过从线条和点获取三角形来计算区域,然后获取包含它的矩形,然后将其膨胀以获得更好的结果...

只有线条?

这个项目也可以修改为其他几何图形,如圆形、椭圆、矩形、多边形等等! 添加更多标记并将它们用作几何点!

结束

是的,就这样了 ;) 我希望这篇文章能帮助到别人,就像其他 Code Project 文章每天都在我的工作中帮助我一样。 请给我发送反馈或/和建议! butch.er@tin.it

再见!

© . All rights reserved.