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






4.73/5 (6投票s)
[教程4] 如何使用 C# 绘制线条以及在端点绘制不同类型的形状,例如矩形和圆形
引言
这是本系列教程的第四讲,教程内容是如何使用 C# 在 Windows 窗体中构建图形程序,并将其导出为矢量格式。
- 教程1---https://codeproject.org.cn/Tips/1082353/tut-GDIplus-Artwork-from-svg
- 教程2---https://codeproject.org.cn/Tips/1082633/interactivaly-add-multiple-shapes-using-linked-lis
- 教程3---https://codeproject.org.cn/Tips/1084073/tut-graphics-program-using-Csharp-Drag-Drop-Delete
……此外,您还将了解如何移动、删除、Ctrl+Z您的矢量图,并将其保存为特殊格式,以便您的程序再次读取。
此外,我们将学习如何保存 XML 文件... 如何导出为 Verilog 格式... 如何使用星形算法... 如何使用手形工具... 如何手动创建撤销技术。
您将能够构建什么
- https://drive.google.com/folderview?id=0B739QmcCMLMHVU1DbHhIQlZ3MTA&usp=sharing
- https://www.youtube.com/watch?v=6hXJ1EoAYc0
今天我将带您了解如何使用 Windows Forms 中的 GDI+ 绘制线条。我还会讨论如何在线条的最后一个点上绘制结束形状。
我们的工作将分为几个部分:
- 创建线条类
- 处理键盘事件以选择线条工具
- 编辑调用线条功能的鼠标方法
- 创建绘制线条的方法
- 编辑 `onpaint` 函数
- 关闭线条
- 在线条类本身创建结束尖端的方法
- 再次编辑键盘事件以结束线条并绘制线条的结束尖端
背景
- 教程1---https://codeproject.org.cn/Tips/1082353/tut-GDIplus-Artwork-from-svg
- 教程2---https://codeproject.org.cn/Tips/1082633/interactivaly-add-multiple-shapes-using-linked-lis
- 教程3---https://codeproject.org.cn/Tips/1084073/tut-graphics-program-using-Csharp-Drag-Drop-Delete
1. 创建一个线条类
线条类是一个简单的类,它只包含两个主要数据类型:
- 线条包含的点列表
- 将要绘制的图形路径本身
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
}
您认为这些教程怎么样?是否达到了您的期望?了解您的反馈对我来说非常重要。