当前位置 : 主页 > 编程语言 > c语言 >

c# – 在visual studio 2013中从面板复制自由手绘图

来源:互联网 收集:自由互联 发布时间:2021-06-25
我想在视觉工作室的一个表格(图片框)中自由地绘制并在另一个面板/图片框上复制相同的图形(我绘制). 它们也不应该是形成一条线而是一条连续线的点.请帮忙. using System;using System.Col
我想在视觉工作室的一个表格(图片框)中自由地绘制并在另一个面板/图片框上复制相同的图形(我绘制).
它们也不应该是形成一条线而是一条连续线的点.请帮忙.

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有一个很好的方法可以画出流畅的线条.你喂它一支笔和一系列点.

这就是我们将要使用的.

让我们回到基础:如何创建图形?现在我们知道你需要在Paint事件中调用DrawCurve:

e.Graphics.DrawCurve(somePen, somePointsArray);

这提出了下一个问题:

>什么是一些人
>什么是somePointsArray

有一个隐藏的第三个问题:

>绘制更多线条怎么样?

第一个很简单;你创建一个笔画宽度为5.5像素的笔

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

如果你愿意,你也可以给它一个linestyle(破折号).

现在为阵列:在最简单的形式,这也很容易..

在MouseMove事件中,您将当前位置存储在点列表中.首先我们在课堂级别声明它:

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会触发系统调用Paint事件.它可能看起来很复杂,但这是唯一正确的方法,因为它保证了当其他一些原因使得必要时也会发生同样的绘图.

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

另请注意,我们不使用数组,因为我们不知道我们需要多少个点.相反,我们使用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.这是一种廉价而安全的方法,可以确保笔被妥善处理.

还要注意我们如何将List转换为数组!

仅上述代码就可以使用,并允许您自由地绘制一条线.

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

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

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

请注意我如何使用从列表到列表的强制转换来强制执行副本,否则只会分配引用,然后在下一行清除..

我们再次触发Paint事件作为最后的事情.

我们现在应该更改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(somePen, currentLine.ToArray());
       foreach (List<Point> lp in curves)
          if (lp.Count > 1) e.Graphics.DrawCurve(somePen, lp.ToArray());
    }
}

现在我们基本上完成了徒手绘图部分.

所以我们回到你原来的问题:如何将图纸复制到第二个面板?

好吧,您已将所有内容存储在曲线数据结构中.

所以你有两个选择:要么只是在panel2_Paint事件中使用相同的数据,要么你需要复制和更改数据,可能适应不同的大小..

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

以下是仍然缺失的事情:

>保存数据,保存图纸(Serialize,DrawToBitMap)
>用不同的笔画和& colors(创建一个drawAction类来存储你需要的所有东西)
>使用Line或Rectangle等其他工具(创建drawAction类)
>清除图纸(见下文)
>撤消和重做(查看堆栈队列)
>当有大量行时缓存(将第一部分绘制到BackgroundImage Bitmap中)

这是清算代码:

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

我注意到您的原始代码允许您使用左右按钮绘制两个不同的笔触宽度.仅这一点就表明这段代码不是很好.谁会a)想到这一点,b)只满足于两个行程宽度..

请阅读this post,其中我解释了一些关于创建一个可以存储笔宽,颜色等的类,以便您可以在绘制的线之间进行更改.

网友评论