绘制多个写意折线或曲线的绘制 - 添加撤消功能 [英] Draw multiple freehand Polyline or Curve drawing - Adding Undo Feature

查看:134
本文介绍了绘制多个写意折线或曲线的绘制 - 添加撤消功能的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我试图创建撤消一个简单的绘图应用程序和重做功能。我想你可以添加你所绘制成一个列表,并呼吁列表绘制的一切。然后,撤消应该只是删除最后一个添加的项目,并再次重绘一切。问题是,如何添加什么我画成一个列表,并使用该列表撤消?



我使用的是位图重新绘制方法。
我这是怎么得出:

 点开始,结束; 
布尔画;
私有列表<&的PointF GT; myPoints =新的List<&的PointF GT;();

私人无效pnlMain_MouseDown(对象发件人,MouseEventArgs E)
{
开始= e.Location;
绘画= TRUE;
}

私人无效pnlMain_MouseUp(对象发件人,MouseEventArgs E)
{
绘画= FALSE;
}

私人无效pnlMain_MouseMove(对象发件人,MouseEventArgs E)
{
如果(油画== true)而
{
端= e.Location;
g.DrawLine(P,开始,结束);
myPoints.Add(e.Location);
pnlMain.Refresh();
开始=结束;
}
}

私人无效btnUndo_Click(对象发件人,EventArgs五)
{
g.Clear(cldFill.Color);
如果(myPoints.Count→2)
{
myPoints.RemoveAt(myPoints.Count - 1);
g.DrawCurve(对,myPoints.ToArray());
}
pnlMain.Refresh();
//这工作,但你必须在垃圾邮件摆脱线的
//并做一些奇怪的连接。
}


解决方案

您需要存储线一个列表与LT;名单<点和GT;> 。列表中的每个元素都包含其中绘制使用下来,移动和向上的图的点。你画的下一行,将在列表中的下一个元素存储。每个撤消,将删除最后的图纸。



把你的窗体上该控件的一个实例,它会处理绘图为您服务。还利用系统

 执行撤消,调用它的撤消方法。 Collections.Generic; 
使用System.Drawing中;
使用System.Linq的;使用System.Windows.Forms的
;





 公共类DrawingSurface:控制
{
公共DrawingSurface(){this.DoubleBuffered = TRUE; }
名单,LT;名单<点和GT;>行=新的List<名单,LT;点和GT;>();
布尔绘图= FALSE;
保护覆盖无效onmousedown事件(MouseEventArgs E){
Lines.Add(新名单<点和GT;());
Lines.Last()添加(e.Location)。
图纸= TRUE;
base.OnMouseDown(E);
}
保护覆盖无效的OnMouseMove(MouseEventArgs E){
如果(图){Lines.Last()添加(e.Location)。 this.Invalidate(); }
base.OnMouseMove(E);
}
保护覆盖无效OnMouseUp(MouseEventArgs E){
如果(图){
this.drawing = FALSE;
Lines.Last()添加(e.Location)。
this.Invalidate();
}
base.OnMouseUp(E);
}
保护覆盖无效的OnPaint(PaintEventArgs的E){
e.Graphics.Smoothi​​ngMode = System.Drawing.Drawing2D.Smoothi​​ngMode.AntiAlias​​;
的foreach(在线路无功项)
e.Graphics.DrawLines(Pens.Black,item.ToArray()); / *或DrawCurve * /
}
公共无效撤消(){
如果(Lines.Count大于0){this.Lines.RemoveAt(Lines.Count - 1); this.Invalidate(); }
}
}

注意




  • 使用这个逻辑,你可以简单地实现重新利用其他列表<名单<点>> 。这足以撤销前的最后一个项目复制使用重做列表 RedoBuffer.Add(Lines.Last()); 。然后,对于每个重做命令,它足以重做缓冲区的最后一个项目添加到和重做缓冲区中取出。你也应该在每次按下鼠标清除重做缓冲区。

  • 您可以使用 DrawLines 或<$ C $的任C> DrawCurve 根据您的要求。 DrawLines 绘制多折线,而 DrawCurve 绘制更加平滑的曲线。


  • 我宁愿封装 Lines.Count> 0 在布尔CanUndo如属性并使其从控制范围之外的访问。


  • 这只是一个例子,你可以简单地扩展解决方案。例如,而不是列表<名单<点>> 您可以创建一个包含<$ C $一个图形类C>列表<点> ,线宽 LineColor 等,并利用执行任务列表与LT;形​​状方式>



I'm trying to create a simple drawing application with undo and redo features. I assume you can add what you are drawing into a list and calling upon the list to draw everything. Then undoing should just remove the last added item and redraw everything again. The problem is, how do I add what I've drawn into a list and use that list to undo?

I'm using the bitmap redraw method. This is how I draw:

    Point start, end;
    bool painting;
    private List<PointF> myPoints = new List<PointF>();

    private void pnlMain_MouseDown(object sender, MouseEventArgs e)
    {
        start = e.Location;
        painting = true;
    }

    private void pnlMain_MouseUp(object sender, MouseEventArgs e)
    {
        painting = false;
    }

    private void pnlMain_MouseMove(object sender, MouseEventArgs e)
    {
        if (painting == true)
        {
            end = e.Location;
            g.DrawLine(p, start, end);
            myPoints.Add(e.Location);
            pnlMain.Refresh();
            start = end;
        }
    }

    private void btnUndo_Click(object sender, EventArgs e)
    {
        g.Clear(cldFill.Color);
        if (myPoints.Count > 2)
        {
            myPoints.RemoveAt(myPoints.Count - 1);
            g.DrawCurve(p, myPoints.ToArray());
        }
        pnlMain.Refresh();
        //This works but you have to spam it to get rid of
        //a line and does some weird connections.
    }

解决方案

You need to store lines in a List<List<Point>>. Each element of the list contains points of a drawing which you draw using a down, move and up. The next line which you draw, will store in the next element of list. Each undo, will remove the last drawing.

Put an instance of this control on your form and it will handle the drawing for you. Also to perform undo, call its Undo method.

using System.Collections.Generic;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;

public class DrawingSurface : Control
{
    public DrawingSurface() { this.DoubleBuffered = true; }
    List<List<Point>> Lines = new List<List<Point>>();
    bool drawing = false;
    protected override void OnMouseDown(MouseEventArgs e) {
        Lines.Add(new List<Point>());
        Lines.Last().Add(e.Location);
        drawing = true;
        base.OnMouseDown(e);
    }
    protected override void OnMouseMove(MouseEventArgs e) {
        if (drawing) { Lines.Last().Add(e.Location); this.Invalidate(); }
        base.OnMouseMove(e);
    }
    protected override void OnMouseUp(MouseEventArgs e) {
        if (drawing) {
            this.drawing = false;
            Lines.Last().Add(e.Location);
            this.Invalidate();
        }
        base.OnMouseUp(e);
    }
    protected override void OnPaint(PaintEventArgs e) {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        foreach (var item in Lines)
            e.Graphics.DrawLines(Pens.Black, item.ToArray()); /*or DrawCurve*/
    }
    public void Undo() {
        if (Lines.Count > 0) { this.Lines.RemoveAt(Lines.Count - 1); this.Invalidate(); }
    }
}

Note

  • Using this logic, you can simply implement redo using an other List<List<Point>>. It's enough to copy the last item before undo to redo list using RedoBuffer.Add(Lines.Last());. Then for each redo command, it's enough to add the last item of redo buffer to Lines and remove it from redo buffer. You should also clear the redo buffer after each mouse down.
  • You can use either of DrawLines or DrawCurve based on your requirement. DrawLines draws a poly-line, while DrawCurve draws a more smooth curve.

  • I prefer to encapsulate Lines.Count > 0 in a property like bool CanUndo and make it accessible from outside of control.

  • It's just an example and you can simply extend the solution. For example, instead of List<List<Point>> you can create a Shape class containing List<Point>, LineWidth, LineColor, etc and perform task using List<Shape>.

这篇关于绘制多个写意折线或曲线的绘制 - 添加撤消功能的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆