Introduction
This is the forth tutorial of a series of tutorials of how to build a graphics program using C# in Windows form that exports the artwork in a vector format.
.... also, you would understand how to move, delete, ctrl z your vector art and save it in a special format to be read by your program again.
Also, we will learn how to save XML files... how to export in verilog format... how to use a star algorithm... how to use hand tool... how to manually create the ctrl z technique.
What you will be capable of building:
Today I am going to walk you through how to draw lines using GDI+ in Windows Forms. I am also going to talk about how to draw an end shape on the last point of your lines.
Our work would be divided to:
- Create a line class
- Work on the keyboard events to choose the line tool
- Edit the mouse method that calls the line function
- Create the method that would create lines
- Edit the
onpaint
function
- Close the line
- Create the method of the end tip in the class of the line itself
- Edit again on keyboard event to end the line and draw the end tip of the line
Background
1. Create a Line Class
The line class is a simple class that would simply contain 2 primary data types:
- List of points that the line contains
- The graphics path itself that would be drawn
public List<Point> point_line = new List<Point>();
public GraphicsPath path_line = new GraphicsPath();
The main concept is to add new points to the list and to use this list in the graphics path, as the graphics path is what is really going to be drawn.
So we would use a simple constructor that simply adds the new point to the list and appends this list to the graphics path.
private void line_action(Point e)
{
point_line.Add(e);
path_line.AddLines(point_line.ToArray()); }
So the class would be:
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. Work on the Keyboard Events to Call the Method of Creating Lines
Now let's return to our main form, and edit the Form1_KeyDown
method, to support drawing lines, let's make it when a user clicks the letter "l
", the line tool would be selected.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
..
.
.
else if (e.KeyData == Keys.L)
{
action = "line";
}
..
.
.
}
3. Edit the Mouse Click Method
We need to edit the mouse click method to take the mouse position and to pass it to the method itself that draws the line, so we would edit Form1_MouseClick
function.
private void Form1_MouseClick(object sender, MouseEventArgs e)
{
..
.
else if (action.Equals("line"))
{
line_action(e);
}
.
.
.
.
}
4. The Method Itself to Draw the Line
Before writing the method, we must first define some important data types, like we have done in the previous tutorials, we would create a list
for lines
:
public static List<lines> lines_list = new List<lines>();
and write a counter
to count lines drawn:
public static int line_counter = 0;
and a bool
to flag the first point of the line:
bool first_point_in_line = true;
Now, we are ready to begin writing the method:
To being in this function, we must differ between the first time you begin drawing the line (so you would add the lines_list
) and the time you edit this line (edit the last line in the lines_list
).
There would be a special section for the first point in the line is drawn=>>to add a new line object to the list and a common section that would really add the point to the array inside the line object (must be the last object in the list so we would use the line_counter
to edit the last object in the list) so we would add this point to the array of points of the line object, and append this list to the graphics path that would really be drawn.
Then we need to update the form with this line so we call Invalidate();
private void line_action(MouseEventArgs e)
{
if (first_point_in_line == true)
{
lines line = new lines(); lines_list.Add(line); first_point_in_line = false; line_counter++; }
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. Edit the onpaint() Function
Edit the onpaint
function to draw the line list.
Don't forget that we use the graphics path inside the line object for drawing and we would draw the arrow (end tip). I will discuss it in the coming sections.
protected override void OnPaint(PaintEventArgs e)
{
..
.
foreach (lines l in lines_list)
{
e.Graphics.DrawPath(l.pen, l.path_line);
e.Graphics.FillPath(Brushes.Black, l.arrow_path_line); }
..
.
}
6. Close the Line
Add a new keyword in the Form1_KeyDown
to close the line, the simple idea is to make the action to be none, and make the first_point_in_line = true
, so that next time you would make a first point for the new line.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
..
.
.
else if (e.KeyData == Keys.Enter)
{
action = "none";
Invalidate();
first_point_in_line = true;
}
.
.
.
.}
Create End Tip Shapes
We would change the end keyword from just enter , to 1 , 2 to choose which end tip type (circle and rectangle). It is a simple concept for adding a graphics path at the last point of the line.
So we would need to edit 2 things the class itself of the line, and let the keyword of ending the line be 1,2 to choose which type of ending type.
1. Edit the Line Class
Define a primary data type to hold the graphics path of the end shape and a pen data type to hold the color of this graphics path, and a string
to tell which type of end tip.
public GraphicsPath arrow_path_line = new GraphicsPath();
public Pen pen = new Pen(Brushes.Black, 2);
public string end_arrow;
Now we would write the function itself.
Simply, we need to select the last point of the list to use as a center point, and then according to the required shape defined in the string
, we will draw the shape.
public void draw_arrow()
{
int number_of_points = this.point_line.Count - 1;
Point last_point = point_line.ElementAt<Point>(number_of_points);
if (end_arrow=="circle") arrow_path_line.AddEllipse(last_point.X - 10, last_point.Y - 10, 20, 20);
else if (end_arrow == "box") {
Rectangle r = new Rectangle(last_point.X - 10, last_point.Y - 10, 20, 20);
arrow_path_line.AddRectangle(r);
}
}
2. Now Define the Keyword to End the Line with Specific Shape
Just select the last line, and define which end tip according to which number is selected 1,2 (circle, box), and call on this line the draw arrow function and then write the same 3 lines of resetting the line tool.
private void Form1_KeyDown(object sender, KeyEventArgs e)
{
..
.
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();
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();
action = "none";
Invalidate();
first_point_in_line = true;
}
.
.
.}
It would be very important for me to know what do you think these tutorials ... are they up to what you have expected ?? ... It would be really important for me to hear your feedback.