绘制多条徒手折线或曲线图 - 添加撤消功能

2024-01-07

我正在尝试创建一个具有撤消和重做功能的简单绘图应用程序。我假设您可以将要绘制的内容添加到列表中,并调用该列表来绘制所有内容。然后撤消应该只是删除最后添加的项目并再次重新绘制所有内容。问题是,如何将绘制的内容添加到列表中并使用该列表撤消?

我正在使用位图重绘方法。 我是这样画的:

    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.
    }

您需要将行存储在List<List<Point>>。列表中的每个元素都包含使用向下、移动和向上绘制的绘图点。您绘制的下一条线将存储在列表的下一个元素中。每次撤消,都会删除最后一个绘图。

将此控件的一个实例放在您的窗体上,它将为您处理绘图。要执行撤消操作,请调用其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

  • 使用此逻辑,您可以简单地使用其他方法实现重做List<List<Point>>。使用以下命令将撤消之前的最后一项复制到重做列表就足够了RedoBuffer.Add(Lines.Last());。然后对于每个重做命令,将重做缓冲区的最后一项添加到Lines并将其从重做缓冲区中删除。您还应该在每次按下鼠标后清除重做缓冲区。
  • 您可以使用其中之一DrawLines or DrawCurve根据您的要求。DrawLines绘制多段线,同时DrawCurve绘制出更平滑的曲线。

  • 我更喜欢封装Lines.Count > 0在像这样的财产bool CanUndo并使其可以从控制之外访问。

  • 这只是一个示例,您可以简单地扩展解决方案。例如,代替List<List<Point>>你可以创建一个Shape类包含List<Point>, LineWidth, LineColor等并使用执行任务List<Shape>.

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

绘制多条徒手折线或曲线图 - 添加撤消功能 的相关文章

  • WPF DataGrid 多选

    我读过几篇关于这个主题的文章 但很多都是来自 VS 或框架的早期版本 我想做的是从 dataGrid 中选择多行并将这些行返回到绑定的可观察集合中 我尝试创建一个属性 类型 并将其添加到可观察集合中 它适用于单个记录 但代码永远不会触发多个
  • 调用 McAfee 病毒扫描引擎

    我收到客户的请求 要求使用他们服务器上的 McAfee 病毒扫描将病毒扫描集成到应用程序中 我做了一些调查 发现 McScan32 dll 是主要的扫描引擎 它导出各种看起来有用的函数 我还发现提到了 McAfee Scan Engine
  • STL 迭代器:前缀增量更快? [复制]

    这个问题在这里已经有答案了 可能的重复 C 中的预增量比后增量快 正确吗 如果是 为什么呢 https stackoverflow com questions 2020184 preincrement faster than postinc
  • 在一个数据访问层中处理多个连接字符串

    我有一个有趣的困境 我目前有一个数据访问层 它必须与多个域一起使用 并且每个域都有多个数据库存储库 具体取决于所调用的存储过程 目前 我只需使用 SWITCH 语句来确定应用程序正在运行的计算机 并从 Web config 返回适当的连接字
  • 通过引用传递 [C++]、[Qt]

    我写了这样的东西 class Storage public Storage QString key const int value const void add item QString int private QMap
  • 机器Epsilon精度差异

    我正在尝试计算 C 中双精度数和浮点数的机器 epsilon 值 作为学校作业的一部分 我在 Windows 7 64 位中使用 Cygwin 代码如下 include
  • free 和 malloc 在 C 中如何工作?

    我试图弄清楚如果我尝试 从中间 释放指针会发生什么 例如 看下面的代码 char ptr char malloc 10 sizeof char for char i 0 i lt 10 i ptr i i 10 ptr ptr ptr pt
  • 为什么 GCC 不允许我创建“内联静态 std::stringstream”?

    我将直接前往 MCVE include
  • 如何使从 C# 调用的 C(P/invoke)代码“线程安全”

    我有一些简单的 C 代码 它使用单个全局变量 显然这不是线程安全的 所以当我使用 P invoke 从 C 中的多个线程调用它时 事情就搞砸了 如何为每个线程单独导入此函数 或使其线程安全 我尝试声明变量 declspec thread 但
  • 重载 (c)begin/(c)end

    我试图超载 c begin c end类的函数 以便能够调用 C 11 基于范围的 for 循环 它在大多数情况下都有效 但我无法理解和解决其中一个问题 for auto const point fProjectData gt getPoi
  • ASP.NET Core 3.1登录后如何获取用户信息

    我试图在登录 ASP NET Core 3 1 后获取用户信息 如姓名 电子邮件 id 等信息 这是我在登录操作中的代码 var claims new List
  • 在 Unity 中实现 Fur with Shells 技术

    我正在尝试在 Unity 中实现皮毛贝壳技术 http developer download nvidia com SDK 10 5 direct3d Source Fur doc FurShellsAndFins pdf Fins 技术被
  • 使用 C# 中的 CsvHelper 将不同文化的 csv 解析为十进制

    C 中 CsvHelper 解析小数的问题 我创建了一个从 byte 而不是文件获取 csv 文件的类 并且它工作正常 public static List
  • 为什么这个字符串用AesCryptoServiceProvider第二次解密时不相等?

    我在 C VS2012 NET 4 5 中的文本加密和解密方面遇到问题 具体来说 当我加密并随后解密字符串时 输出与输入不同 然而 奇怪的是 如果我复制加密的输出并将其硬编码为字符串文字 解密就会起作用 以下代码示例说明了该问题 我究竟做错
  • 如何在 Linq to SQL 中使用distinct 和 group by

    我正在尝试将以下 sql 转换为 Linq 2 SQL select groupId count distinct userId from processroundissueinstance group by groupId 这是我的代码
  • C 函数 time() 如何处理秒的小数部分?

    The time 函数将返回自 1970 年以来的秒数 我想知道它如何对返回的秒数进行舍入 例如 对于100 4s 它会返回100还是101 有明确的定义吗 ISO C标准没有说太多 它只说time 回报 该实现对当前日历时间的最佳近似 结
  • 使用特定参数从 SQL 数据库填充组合框

    我在使用参数从 sql server 获取特定值时遇到问题 任何人都可以解释一下为什么它在 winfom 上工作但在 wpf 上不起作用以及我如何修复它 我的代码 private void UpdateItems COMBOBOX1 Ite
  • 对于某些 PDF 文件,LoadIFilter() 返回 -2147467259

    我正在尝试使用 Adob e IFilter 搜索 PDF 文件 我的代码是用 C 编写的 我使用 p invoke 来获取 IFilter 的实例 DllImport query dll SetLastError true CharSet
  • 在OpenGL中,我可以在坐标(5, 5)处精确地绘制一个像素吗?

    我所说的 5 5 正是指第五行第五列 我发现使用屏幕坐标来绘制东西非常困难 OpenGL 中的所有坐标都是相对的 通常范围从 1 0 到 1 0 为什么阻止程序员使用屏幕坐标 窗口坐标如此严重 最简单的方法可能是通过以下方式设置投影以匹配渲
  • 指针和内存范围

    我已经用 C 语言编程有一段时间了 但对 C 语言还是很陌生 有时我对 C 处理内存的方式感到困惑 考虑以下有效的 C 代码片段 const char string void where is this pointer variable l

随机推荐

  • WPF:自定义区域设置

    我今天刚刚发现 WPF 将忽略 CultureInfo CurrentCulture 并始终使用 en US 我也找到了一个很棒的答案here https stackoverflow com questions 2764615 wpf st
  • Android 数据绑定与自定义适配器

    我正在尝试使用Android 的数据绑定功能 http developer android com tools data binding guide html使用自定义适配器和 ListView 我在覆盖自定义适配器时遇到问题getView
  • 如何在 bash for 循环中执行 psql 命令

    我想在 bash 脚本中执行 psql 语句并将结果输出到文件中 我下面的代码可以按需要工作 bin bash query select from mytable psql lt
  • 如何将 FlexBox 项目扩展到全屏而不移动其他 Flex 项目?

    我有一个盒子的弹性盒子布局 单击这些框时 它们会扩展为全屏 问题是 当盒子展开时 它会移动其他弹性元素 导致动画看起来跳跃 弹性布局还可以防止展开的框接触屏幕顶部 这是一个小提琴 向您展示我在说什么 fiddle https jsfiddl
  • WPF 通过覆盖方法更新 UI 不起作用

    我正在尝试从 ViewModel 更新 WPF UI 风景
  • 什么是 JSP 上下文?

    我想知道这个 java 对象到底是什么以及它的主要用途是什么 我看过java文档 但这让我更困惑 它是否有会话 请求 应用程序等关系范围 JspContext JspContext 令人困惑 因为它似乎没有做任何 ServletContex
  • 如何在Python中反转字典(其值是列表)? [复制]

    这个问题在这里已经有答案了 我想编写一个函数 它接收字典作为输入参数并返回输入字典的反向值 其中原始字典的值用作返回字典的键 原始字典的键用作返回字典的值返回的字典解释如下 dict Accurate exact precise exact
  • 如何使用 septice 在明火中创建持久房间?

    我正在使用以下内容iq在 openfire 中创建持久房间的消息 var configiq iq to chatObj getActiveChatRoomName chatObj groupChatService type set c x
  • 使用js将字符串附加到图像src

    我有一个页面 里面有 img src images product whatever image jpg alt 我希望在加载页面时 将字符串 Action thumbnail 附加到 src 的值 使其成为src images produ
  • 为什么stream api不是为异常处理而设计的?

    Fixtures BiConsumer
  • 使用 Python 读取 UTF8 CSV 文件

    我正在尝试使用 Python 读取带有重音字符的 CSV 文件 仅限法语和 或西班牙语字符 基于 csvreader 的 Python 2 5 文档 http docs python org library csv html http do
  • 使用光流进行特征跟踪

    我找到了一个类似的问题 https stackoverflow com questions 9701276 opencv tracking using optical flow 9702540 comment13031247 9702540
  • 将材质图标与样式组件一起使用

    刚刚开始使用样式组件 有没有办法设置第三方图标 例如 Material Design Icon 的样式 这是我到目前为止的代码 但显然它不起作用 相关代码位于内容组件下方 Thanks const MaterialIcon props gt
  • localStorage html5 功能在 Samsung Android 设备上的 WebView 中不起作用

    我有一个用 WebView 包装的 html5 应用程序 为了在页面之间存储和检索用户输入值 我使用本地存储html5 功能 它在我的 Nexus 4 Android 4 4 4 上运行良好 但在 Samsung Galaxy Tab 2
  • 罗马尼亚语区域设置

    经过谷歌搜索一段时间后 我发现 Android 2 3 版本确实支持它 但我没有找到它支持的最低版本 如果 Android 2 2 版本不支持罗马尼亚语那么有什么替代方案 感谢您的关注 这是已解决的类似问题 Android 支持的语言 区域
  • 使用正则表达式检查文本框不允许小数

    我想创建一个 TextChanged 事件来检查输入文本是否符合特定条件 如果不符合则删除最后输入的字符 在本例中 标准是数字 1 位小数和 1 位分数 我正在测试仅用于数字和小数的正则表达式 并遇到了问题 我尝试了几种不同的表达式 我不擅
  • 如何在 Laravel 代码中嵌入视频

    我正在开发一个项目 在该项目中 我将 youtube 视频链接存储在数据库中 然后检索这些链接并使用刀片模板引擎尝试将它们嵌入到页面中 我使用循环将视频放入页面中 由于某种原因 我在浏览器中看不到任何视频 它覆盖了提到的空间 但不渲染任何东
  • QSqlQuery size() 总是返回-1

    QSqlQuery query QString queryText SELECT FROM section query exec queryText qDebug lt lt query size always 1 while query
  • ViewPager Fragments 未在 onCreate 中启动

    我似乎在更新 ViewPager 中使用的片段时遇到问题 无论我尝试使用 onCreate onCreateView 还是 onResume 以下是我在 MainFragment 中设置 ViewPager 的方法 public View
  • 绘制多条徒手折线或曲线图 - 添加撤消功能

    我正在尝试创建一个具有撤消和重做功能的简单绘图应用程序 我假设您可以将要绘制的内容添加到列表中 并调用该列表来绘制所有内容 然后撤消应该只是删除最后添加的项目并再次重新绘制所有内容 问题是 如何将绘制的内容添加到列表中并使用该列表撤消 我正