更新绘图而不删除之前的绘图

Update a drawing without deleting the previous one

我在绘图方法中创建了这个

private void draws()
{
 Bitmap bmp = new Bitmap(pictureBox17.Width, pictureBox17.Height);
 using (Graphics g = Graphics.FromImage(bmp))
            {
                //define area do pictureBox17 e preenche a branco
                Brush brush = new SolidBrush(Color.White);
                Rectangle area = new Rectangle(0, 0, pictureBox17.Width, pictureBox17.Height);
                g.FillRectangle(brush, area);
                //desenha as linhas do rectangulo
                g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
// some more lines
}
 pictureBox17.Image = bmp;
}

它画的正是我想要的。但是想象一下,在这之后我想更新完全相同的绘图,添加几行,而不必重新绘制,这可能吗?显然我正在使用方法

draws();

然后我想补充一些东西,有什么提示吗?

尝试在函数外部创建位图以保存它,您现在的做法是在函数完成后处理位图元素。

然后你可以做类似

Bitmap bmp = new Bitmap(pictureBox17.Width, pictureBox17.Height);
    private void draws()
    {
     if (bmp ==null)
     using (Graphics g = Graphics.FromImage(bmp))
                {
                    //define area do pictureBox17 e preenche a branco
                    Brush brush = new SolidBrush(Color.White);
                    Rectangle area = new Rectangle(0, 0, pictureBox17.Width, pictureBox17.Height);
                    g.FillRectangle(brush, area);
                    //desenha as linhas do rectangulo
                    g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
                 }
   else {
         using (Graphics g = Graphics.FromImage(bmp))
         {
            g.DrawLine(new Pen(Color.Black), esp, esp, esp, yWcorrigidoesp);
         }
    // some more lines
    }
     pictureBox17.Image = bmp;
    }

只是为了让你开始.. :)

或者,如果您使用此方法在不同时间绘制多个 bmp,则可以将 bmp 传递给 draw 函数

方法是创建一个 DrawAction class 来保存你想要绘制的东西所需的所有数据:Point 数据,PenBrush

然后您创建并管理 List<DrawAction> drawActions 然后您有一个选择:

  • 您要么在 PictureBoxPaint 事件中完成所有绘图 'live',要么 Panel(或 任何 控制与 Paint 事件)通过循环列表..

  • ..或者您将新操作 添加到您正在构建的 Bitmap Image

什么更好真的取决于:你是否希望进行动态绘图,比如通过用户操作?您想要 undo/redo 选项吗?然后实时绘图控制面更适合。

或者待办事项列表是固定的还是从一组固定的数据中派生出来的,并且最终会保存到磁盘中。这听起来更像是将 绘制到 位图中。

两者也可以组合,也许可以收集一些动作,同时保留撤消选项(通过删除最后一个列表项)并提供应用 按钮将它们泵入位图中..

注意:绘图的关键是将绘图数据保存在列表中,以便您在需要时可以使用它再一次,展开和删除列表,甚至更改它:遍历所有操作并更改 ColorWidthLineStyle 将是一个简单的两行代码Pen 或稍微移动 Points 等等!

当您创建 DrawAction class 时,如果您可以决定需要执行哪些操作,这会有所帮助。如果你不能,你仍然可以选择一个更扩展的 class,有足够的成员来使用 Graphics class 提供的所有选项:DrawxxFillxxx, Pen 属性, Colors 甚至可以缩放..

对于初学者来说,一个类型,一个List<Point>一个float PenWidth和一个Color就可以了..

这里有一个简单的例子 class,Paint 事件,添加一些测试动作的代码和 both:

  • 一个用于实时绘图和..
  • 的按钮
  • ..one 将操作应用于 PictureBox.
  • 的位图 Image

测试数据为一个Line和一组Polylines

您应该通过定义一个 Enum 来开始改进它,其中包含您要使用的所有绘图动作类型!这将更好、更容易理解我编写的廉价字符类型 ;-) 类型可能包括 Rectangle, FilledRectangle, Ellipse, FilledEllipse, Line, Lines, Polygon, FilledPolygon, Text, Curve, Curves 等等。再加上一点额外的东西,你还可以使用图像、图形路径、样条曲线。其他数据可以控制 Rotation, Scaling, Gradients, Transparency 等。

List<DrawAction> actions = new List<DrawAction>();

public class DrawAction
{
    public char type { get; set; }             // this should be an Enum!
    public Color color { get; set; }     
    public float penWidth { get; set; }        // only one of many Pen properties!
    public List<Point> points { get; set; }    // use PointF for more precision

    public DrawAction(char type_, Color color_, float penwidth_)
    {
        type = type_; color = color_; penWidth = penwidth_;
        points = new List<Point>();
    }
}

private void pictureBox1_Paint(object sender, PaintEventArgs e)
{
    Draw(e.Graphics, actions);
}


public void Draw(Graphics G, List<DrawAction> actions)
{
    foreach (DrawAction da in actions)
        if (da.type == 'L' && da.points.Count > 1)
            using (Pen pen = new Pen(da.color, da.penWidth))
                G.DrawLine(pen, da.points[0], da.points[1]);
        else if (da.type == 'P' && da.points.Count > 1)
            using (Pen pen = new Pen(da.color, da.penWidth))
                G.DrawLines(pen, da.points.ToArray());
    // else..


}

private void button1_Click(object sender, EventArgs e)
{
    AddTestActions();
    pictureBox1.Invalidate();
}

private void button2_Click(object sender, EventArgs e)
{
    AddTestActions();
    Bitmap bmp = new Bitmap(pictureBox1.ClientSize.Width, 
                            pictureBox1.ClientSize.Height);
    using (Graphics G = Graphics.FromImage(bmp))  Draw(G, actions);
    pictureBox1.Image = bmp;
}

void AddTestActions()
{
    actions.Add(new DrawAction('L', Color.Blue, 3.3f));
    actions[0].points.Add(new Point(23, 34));
    actions[0].points.Add(new Point(23, 134));
    actions.Add(new DrawAction('P', Color.Red, 1.3f));
    actions[1].points.Add(new Point(11, 11));
    actions[1].points.Add(new Point(55, 11));
    actions[1].points.Add(new Point(55, 77));
    actions[1].points.Add(new Point(11, 77));
}

两者的结果看起来一样:

Update 另一个可能更合适的设计是在 DrawAction class 中有一个 Draw (Graphics g) 方法。然后在 Paint 事件中这样做:foreach (DrawAction da in drawActionList) da.Draw(e.Graphics);