2013 年 visual studio 从面板复制自由手绘图

copying free hand drawing from panel in visual studio 2013

我想在 visual studio 上的表格(图片框)中徒手绘制并在另一个 panel/picture 框上复制相同的图形(我绘制的)。 它们也不应该是形成一条线的点,而是一条连续的线。请帮忙

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Data;
using System.Drawing;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows.Forms;

namespace WindowsFormsApplication1
{
    public partial class Form1 : Form
    {
        Pen p_white;

        bool draw = true;

        private Graphics objgraphics;

        public Form1()
        {
            InitializeComponent();
        }

        private void button1_Click(object sender, EventArgs e)
        {
        }

        private void panel1_Paint(object sender, PaintEventArgs e)
        {
            Pen p_black = new Pen(new SolidBrush(Color.Black));

            if (draw)
            {
                objgraphics = panel1.CreateGraphics();

            }

        }

        /*private void panel1_MouseDown(object sender, MouseEventArgs e)
        {
            bool draw = true;
        }*/

        private void panel1_MouseMove_1(object sender, MouseEventArgs e)
        {
                      Rectangle rEllipse = new Rectangle();


            switch (e.Button)
            {

                case MouseButtons.Left:

                    rEllipse.X = e.X;
                    rEllipse.Y = e.Y;
                    rEllipse.Width = 5;
                    rEllipse.Height = 5;
                    objgraphics.DrawEllipse(System.Drawing.Pens.Black, rEllipse);
                    break;

                case MouseButtons.Right:

                    rEllipse.X = e.X;
                    rEllipse.Y = e.Y;
                    rEllipse.Width = 3;
                    rEllipse.Height = 3;
                    objgraphics.DrawEllipse(System.Drawing.Pens.Black, rEllipse);
                    break;

                default:
                    return;
           } 

        }

        /*private void panel1_MouseUp(object sender, MouseEventArgs e)
        {
            bool draw = false;
        } */

        private void form_Paint(object sender, EventArgs e)
        {

        }

        private void panel2_Paint(object sender, PaintEventArgs e)
        {

            Pen p_black = new Pen(new SolidBrush(Color.Black));

            if (draw)
            {                objgraphics = panel1.CreateGraphics();

            }

        }

        private void button2_Click(object sender, EventArgs e)
        {
            this.Close();
        }

    }
}

看着你的代码恐怕我不得不说:这是完全错误的

抱歉这么直白,但是你绝不能使用control.CreateGraphics!!

  • 首先要做的是扔掉Graphics objgraphics对象。

存储 Graphics 对象(几乎)总是错误的!

相反,您必须使用从控件 Paint 事件中的 e.Graphics 参数获得的参数。

请注意 Graphics 不包含 任何图形,它是一种用于在关联的 Bitmap 或控件表面上绘图的工具。

  • 接下来要做的就是了解徒手画线。人们通常可以看到您拥有的代码;但它是无用的,只是你在介绍中发现了多少愚蠢的东西的一个例子。算了吧。它总是看起来像废话,因为圆圈看起来永远不会平滑,而且一旦您更快地移动鼠标,伪线就会完全分崩离析。

有一个很好的方法 DrawCurve 可以画出流畅的线条。你给它一个 Pen 和一个 Points.

的数组

这就是我们要使用的。

让我们return了解基础知识:如何创建图形?现在我们知道您需要在 Paint 事件中调用 DrawCurve

e.Graphics.DrawCurve(somePen, somePointsArray);

这带来了下一个问题:

  • 什么是笔
  • 什么是 somePointsArray

还有个隐藏的第三题:

  • 画更多的线怎么样?

第一个很简单;您创建了一个笔画宽度为 5.5 像素的 Pen 作为

Pen somePen = new Pen(Color.Blue, 5.5f); 

如果你愿意,你也可以给它一个线型(破折号)。

现在是数组:在最简单的形式中,这也很容易..

MouseMove 事件中,您将当前 Location 存储在点列表中。首先我们在 class 级别声明它:

List<Point> currentLine = new List<Point>();

然后我们只要按下左键就开始填充:

private void panel1_MouseMove_1(object sender, MouseEventArgs e)
{
    if (e.Button == System.Windows.Forms.MouseButtons.Left)
    {
        currentLine.Add(e.Location);
        panel1.Invalidate();
    }  
}

注意最后一行:在控件上调用 Invalidate 会触发 system 以调用 Paint 事件。它可能看起来很复杂,但这是唯一正确的方法,因为它保证在某些 其他 原因需要时也会出现相同的绘图。

我们需要绘制,因为我们改变了应该绘制的数据。但是有许多 外部 原因,最臭名昭著的 Minimize/maximize 序列将清除绘图并触发 Paint 事件。所以我们需要配合windows绘制控件的方式!只有这样图形才会 持续存在 .

另请注意,我们不使用数组,因为我们不知道需要多少 Points。相反,我们使用 List 然后将其转换为 Array..

让我们为我们的简单案例编写 Paint 事件代码:

private void panel1_Paint(object sender, PaintEventArgs e)
{
   using (Pen somePen = new Pen(Color.Blue, 5.5f) )
     if (currentLine.Count > 1) e.Graphics.DrawCurve(yourPen , currentLine.ToArray());
}

请注意,我在 using 子句中创建了 Pen。这是确保妥善处理 Pen 的一种廉价且安全的方法。

另请注意我们如何将 List 转换为 Array!

仅上面的代码就可以工作,并允许您徒手画一条线。

但是下一行呢?它不应该连接到第一个,所以我们不能只添加更多点!

所以我们不仅需要一个点列表,还需要更多点列表,实际上需要一个点列表:

List<List<Point>> curves = new List<List<Point>>();

并且只要松开鼠标,我们就将当前曲线添加到其中:

private void panel1_MouseUp(object sender, MouseEventArgs e)
{
    if (currentLine.Count > 1) curves.Add(currentLine.ToList());  // copy!!
    currentLine.Clear();
    panel1.Invalidate();
}

请注意我是如何使用从 ListList 的强制转换来强制复制的,否则只会分配引用,然后在下一行中清除..

我们再次触发 Paint 事件作为最后要做的事情。

我们现在应该更改 Paint 事件以显示所有线条,包括当前正在绘制的线条和所有较早的线条..:[=​​61=]

private void panel1_Paint(object sender, PaintEventArgs e)
{
    using (Pen somePen = new Pen(Color.Blue, 5.5f) )
    {
       if (currentLine.Count > 1) e.Graphics.DrawCurve(somePen, currentLine.ToArray());
       foreach (List<Point> lp in curves)
          if (lp.Count > 1) e.Graphics.DrawCurve(somePen, lp.ToArray());
    }
}

至此写意部分基本完成

所以我们 return 你原来的问题:如何将绘图复制到 second Panel?

好了,您已经将所有内容存储在 curves 数据结构中。

所以你有两个选择:要么简单地在 panel2_Paint 事件中使用相同的数据,要么如果你需要复制和更改数据,也许适应不同的大小..

SO 不是代码编写服务。所以通常我不应该给你比我在上面的评论中写的更多的提示。但是由于这个问题经常出现,我写了一个非常基本的涂鸦应用程序的完整代码..

这里还缺少一些东西:

  • 保存数据,保存绘图(Serialize,DrawToBitMap)
  • 用不同的笔和颜色绘图(创建一个 drawAction class 来存储你需要的所有东西)
  • 使用直线或矩形等其他工具(创建 drawAction class)
  • 正在清除绘图(见下文)
  • 撤消和重做(查看 StacksQueues
  • 行数较多时缓存(将第一部分画成BackgroundImage Bitmap

这里是清算码:

curves.Clear(); currentLine .Clear(); panel1.Invalidate();

我注意到您的原始代码允许您使用左右按钮以两种不同的笔画宽度进行绘制。仅此一点就说明这段代码不是很好。谁会 a) 想到那个 b) 只满足于两个笔划宽度..

请阅读 ,我在其中解释了一些有关创建 class 的内容,它可以存储笔宽、颜色等,以便您可以在绘制的线条之间进行更改..