65.9K
CodeProject 正在变化。 阅读更多。
Home

[教程4] 绘制带有圆形和矩形端点的线条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.73/5 (6投票s)

2016 年 6 月 7 日

CPOL

5分钟阅读

viewsIcon

21831

downloadIcon

599

[教程4] 如何使用 C# 绘制线条以及在端点绘制不同类型的形状,例如矩形和圆形

引言

这是本系列教程的第四讲,教程内容是如何使用 C# 在 Windows 窗体中构建图形程序,并将其导出为矢量格式。

……此外,您还将了解如何移动、删除、Ctrl+Z您的矢量图,并将其保存为特殊格式,以便您的程序再次读取。

此外,我们将学习如何保存 XML 文件... 如何导出为 Verilog 格式... 如何使用星形算法... 如何使用手形工具... 如何手动创建撤销技术。

您将能够构建什么

今天我将带您了解如何使用 Windows Forms 中的 GDI+ 绘制线条。我还会讨论如何在线条的最后一个点上绘制结束形状。

我们的工作将分为几个部分:

  1. 创建线条类
  2. 处理键盘事件以选择线条工具
  3. 编辑调用线条功能的鼠标方法
  4. 创建绘制线条的方法
  5. 编辑 `onpaint` 函数
  6. 关闭线条

 

  1. 在线条类本身创建结束尖端的方法
  2. 再次编辑键盘事件以结束线条并绘制线条的结束尖端

背景

1. 创建一个线条类

线条类是一个简单的类,它只包含两个主要数据类型:

  1. 线条包含的点列表
  2. 将要绘制的图形路径本身
 public List<Point> point_line = new List<Point>();
 public GraphicsPath path_line = new GraphicsPath();

核心思想是将新点添加到列表中,并使用此列表来创建图形路径,因为图形路径才是真正要绘制的内容。

因此,我们将使用一个简单的构造函数,它只需将新点添加到列表中,然后将该列表附加到图形路径中。

  private void line_action(Point e)
        {
            point_line.Add(e);
            path_line.AddLines(point_line.ToArray());//append the list to the end of th graphics path
        }

所以类将是这样的:

 public   class lines
    {
        public List<Point> point_line = new List<Point>();
        public GraphicsPath path_line = new GraphicsPath();

        private void line_action(Point e)
        {
            point_line.Add(e);
            path_line.AddLines(point_line.ToArray());
        }
    }

2. 处理键盘事件以调用创建线条的方法

现在让我们回到主窗体,编辑 `Form1_KeyDown` 方法,以支持绘制线条。我们将其设置为当用户按下字母“l”时,选择线条工具。

  private void Form1_KeyDown(object sender, KeyEventArgs e)
{
.//old code
.
.
.


//new code
else if (e.KeyData == Keys.L)
            {
                action = "line";
            }
//new code


.//old code
.
.
.        
}

3. 编辑鼠标单击方法

我们需要编辑鼠标单击方法,以获取鼠标位置并将其传递给绘制线条本身的方法,因此我们将编辑 `Form1_MouseClick` 函数。

 private void Form1_MouseClick(object sender, MouseEventArgs e)
{
.//old code
.
.


//new code
   else if (action.Equals("line"))
            {
                line_action(e);
            }
//new code


.
.
.
.//old code

} 

4. 绘制线条的方法本身

在编写方法之前,我们必须首先定义一些重要的数据类型。就像我们在之前的教程中所做的那样,我们将创建一个 `lines` 列表:

        public static List<lines> lines_list = new List<lines>(); 

并编写一个 `counter` 来计算绘制的线条数:

        public static int line_counter = 0;

以及一个 `bool` 来标记线条的第一个点:

        bool first_point_in_line = true;

现在,我们准备开始编写方法了。

在此函数中开始时,我们必须区分您第一次开始绘制线条(此时您将添加 `lines_list`)和您编辑此线条的时候(编辑 `lines_list` 中的最后一条线)。

将有一个 **特殊部分** 用于绘制线条的第一个点 => 用于将新线条对象添加到列表中,以及一个 **通用部分**,它将实际将点添加到线条对象内的数组中(必须是列表中的最后一个对象,因此我们将使用 `line_counter` 来编辑列表中的最后一个对象),因此我们将此点添加到线条对象的点数组中,并将此列表附加到将要实际绘制的图形路径中。

然后我们需要更新窗体以显示此线条,因此我们调用 `Invalidate();`

private void line_action(MouseEventArgs e)
{
    //special section
    if (first_point_in_line == true)
            {
                lines line = new lines();//create an object of the type line
                lines_list.Add(line);//add it to the list
                first_point_in_line = false;//let the bool be false
                line_counter++;//increment the counter
            }

  //common section
  lines current_line = new lines();
  current_line = lines_list.ElementAt<lines>(line_counter - 1);

  Point Point_line = new Point();
  Point_line.X = e.Location.X ;
  Point_line.Y = e.Location.Y;
  current_line.point_line.Add(Point_line);

  GraphicsPath a = new GraphicsPath();
  current_line.path_line = a;
  current_line.path_line.AddLines(current_line.point_line.ToArray());

 Invalidate();
}

5. 编辑 onpaint() 函数

编辑 `onpaint` 函数以绘制线条列表。

别忘了我们在线条对象中使用图形路径进行绘制,并且我们将绘制箭头(结束尖端)。我将在接下来的部分讨论它。

protected override void OnPaint(PaintEventArgs e)
{
.//old code
.
.

//new code
 foreach (lines l in lines_list)
            {
                e.Graphics.DrawPath(l.pen, l.path_line);
                e.Graphics.FillPath(Brushes.Black, l.arrow_path_line);//we will discuss it in the 
                                                                      //coming sections
            }
//new code

.//old code
.
.
}

6. 关闭线条

在 `Form1_KeyDown` 中添加一个新关键字来关闭线条。简单的想法是使操作无效,并将 `first_point_in_line = true`,这样下次您就可以为新线条创建第一个点。

  private void Form1_KeyDown(object sender, KeyEventArgs e)
{
.//old code
.
.
.

//new code
else if (e.KeyData == Keys.Enter)
            {
                action = "none";
                Invalidate();
                first_point_in_line = true;
            }
//new code

.
.
.
.//old code
}  

创建结束尖端形状

我们将结束关键字从仅输入更改为 1、2 来选择结束尖端类型(圆形和矩形)。它是一种在线条最后一个点添加图形路径的简单概念。

因此,我们需要编辑两件事:线条类本身,以及让结束线条的关键字为 1、2 来选择结束类型的类型。

1. 编辑线条类

定义一个主数据类型来存储结束形状的图形路径,一个笔数据类型来存储此图形路径的颜色,以及一个 `string` 来指示结束尖端的类型。

 public GraphicsPath arrow_path_line = new GraphicsPath();
 public Pen pen = new Pen(Brushes.Black, 2);

 public string end_arrow;

现在我们将编写函数本身。

简单来说,我们需要选择列表的最后一个点作为中心点,然后根据 `string` 中定义的所需形状,绘制该形状。

 public void draw_arrow()
        {
            int number_of_points = this.point_line.Count - 1;
            Point last_point = point_line.ElementAt<Point>(number_of_points);//select last point

            if (end_arrow=="circle")//elipse having center of that of the last point 
                                    //but shifted by 10 pixels in x and y 
                                    //and a height and width of 20 and 20
                arrow_path_line.AddEllipse(last_point.X - 10, last_point.Y - 10, 20, 20);

            else if (end_arrow == "box")//rectangle having center of that of the last point
                                        //but shifted by 10 pixels in x and y
                                        //and a height and width of 20 and 20
            {
                Rectangle r = new Rectangle(last_point.X - 10, last_point.Y - 10, 20, 20);
                arrow_path_line.AddRectangle(r);
            }
        }

2. 现在定义用特定形状结束线条的关键字

只需选择最后一条线,并根据所选的数字 1、2(圆形、框)定义结束尖端,并在此线上调用绘制箭头函数,然后编写相同的 3 行来重置线条工具。

private void Form1_KeyDown(object sender, KeyEventArgs e)
{
.//old code
.
.

//new code
            else if (e.KeyData == Keys.NumPad1)
            {
                lines current_line = new lines();
                current_line = lines_list.ElementAt<lines>(line_counter - 1);
                current_line.end_arrow = "circle";
                current_line.draw_arrow();

                //resetting the line tool 
                action = "none";
                Invalidate();
                first_point_in_line = true;
            }

            else if (e.KeyData == Keys.NumPad2)
            {
                lines current_line = new lines();
                current_line = lines_list.ElementAt<lines>(line_counter - 1);
                current_line.end_arrow = "box";
                current_line.draw_arrow();

                //resetting the line tool 
                action = "none";
                Invalidate();
                first_point_in_line = true;
            }
//new code

.
.
.//old code
}
您认为这些教程怎么样?是否达到了您的期望?了解您的反馈对我来说非常重要。
© . All rights reserved.