Stefan N
Stefan N

Reputation: 73

Why does my program draw all the lines from the top left corner? How to change this?

I have written a program that is supposed to connect 10 points generated by mouseclicks, with lines.

I am the following problems:

it draws all lines from the top left corner. I can think of the solution being something along the lines of setting the first point as the first mouseclick, but i do not know how to do this.

code:


    public partial class Form1 : Form

    {
        Point[] punten = new Point[10];
        private int kliks = 0;
        private int lijst = 0;

        public Form1()
        {
            InitializeComponent();
        }

        private void Form1_MouseClick(object sender, MouseEventArgs e)
        {

           
         kliks = kliks + 1;
            lijst = kliks;
            punten[lijst] = e.Location;

            if (lijst < 9)


            {
                punten[lijst] = e.Location;

            }

            else
            {

                Pen pen = new Pen(Color.Blue);
                Graphics papier = this.CreateGraphics();
                papier.DrawLines(pen, punten);
            }
        }
    }
}

        

Upvotes: 0

Views: 110

Answers (1)

John Alexiou
John Alexiou

Reputation: 29244

The problem for you is using a fixed-size array. Each entry defaults to a point (0,0) and so the Drawlines() method draws the 10 elements, even the ones not set by mouseclicks. This results in the final few points begin at the origin (0,0). In addition, there is a buggy implementation of which clicks to keep and how many have happened in using kliks and lijst for the same thing.

This being C#, it is better to learn how to separate your data model that keeps track of your mouselicks and your display codes that draws the lines.

PointHistory.cs

Consider the following class that uses an array of Point to keep track of the mouseclicks. The class is initialized with the maximum number of points to keep (here 10 for example). There are methods for adding a point AddPoint(point) and to remove the oldest point with RemoveFirstPoint(). The number of points defined is viewed with the .Count property.

Finally, the GetPoints() method, returns a copy of the array with only the elements that have been defined. This method is used in the code that draws the lines.

using System;
using System.Linq;

public class PointHistory
{
    private readonly Point[] points;
    private readonly int maxPoints;
    private int count;

    public PointHistory(int pointCapacity)
    {
        count = 0;
        maxPoints = pointCapacity;
        points = new Point[pointCapacity];
    }

    public Point[] GetPoints() { return points.Take(count).ToArray(); }
    public int Count { get => count; }
    public int Capacity { get => maxPoints; }
    public void AddPoint(Point point)
    {
        if (count < maxPoints)
        {
            points[count++] = point;
        }
    }
    public void RemoveFirstPoint()
    {
        if (count > 0)
        {
            for (int i = 0; i < count - 1; i++)
            {
                points[i] = points[i + 1];
            }
            count--;
        }
    }
}

Form1.cs

Another issue is your drawing, which needs to happen in Paint event handler. Use your MouseClick event to modify the list of points, and the Paint event to do the drawing.

public partial class Form1 : Form
{
    readonly PointHistory history;

    public Form1()
    {
        InitializeComponent();

        history = new PointHistory(10);
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        this.MouseClick += Form1_MouseClick;
        this.Paint += Form1_Paint;
    }

    private void Form1_MouseClick(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            history.AddPoint(e.Location);
        }
        else if (e.Button == MouseButtons.Right)
        {
            history.RemoveFirstPoint();
            history.AddPoint(e.Location);
        }
        this.Invalidate();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        if (history.Count >= 2)
        {
            e.Graphics.DrawLines(Pens.Blue, history.GetPoints());
        }
        foreach (var point in history.GetPoints())
        {
            e.Graphics.FillEllipse(Brushes.Blue, point.X - 2, point.Y - 2, 4, 4);
        }
    }

}

I have added some extra code to add little dots at the mouse clicks for a better visual effect.

Left button clicks try to add points to the history of mouseclicks, up to the limit set in the constructor for PointHistory. The right mousebutton cicks removes the oldest point first before adding the new point.

fig1


Based on the comments, I want to present a version below that does not define a separate class for the logic, and everything is done internally withing the Form1 class. Also no advanced libraries such as Linq are used

public partial class Form1 : Form
{
    private readonly Point[] points;
    private int count;

    public Form1()
    {
        InitializeComponent();

        points = new Point[10];
        count = 0;
    }

    protected override void OnLoad(EventArgs e)
    {
        base.OnLoad(e);

        this.Paint += Form1_Paint;
        this.MouseClick += Form1_MouseClick;
    }

    public Point[] GetPoints()
    {
        Point[] results = new Point[count];
        for (int i = 0; i < count; i++)
        {
            results[i] = points[i];
        }
        return results;

        // Alternative to the loop above
        //
        //Array.Copy(points, results, count);
        //return results;
    }
    public void AddPoint(Point point)
    {
        if (count < points.Length)
        {
            points[count++] = point;
        }
    }
    public void RemoveFirstPoint()
    {
        if (count > 0)
        {
            for (int i = 0; i < count - 1; i++)
            {
                points[i] = points[i + 1];
            }
            count--;
        }
    }

    private void Form1_MouseClick(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            AddPoint(e.Location);
        }
        else if (e.Button == MouseButtons.Right)
        {
            RemoveFirstPoint();
            AddPoint(e.Location);
        }
        this.Invalidate();
    }

    private void Form1_Paint(object sender, PaintEventArgs e)
    {
        e.Graphics.SmoothingMode = System.Drawing.Drawing2D.SmoothingMode.AntiAlias;
        Point[] mouseClicks = GetPoints();
        if (count >= 2)
        {
            e.Graphics.DrawLines(Pens.Blue, mouseClicks);
        }
        foreach (var point in mouseClicks)
        {
            e.Graphics.FillEllipse(Brushes.Blue, point.X - 2, point.Y - 2, 4, 4);
        }
    }

}

The main method to look at is GetPoints() which returns an array of points that have been defined by mouse clicks and ignores any points that have not been defined yet.

There is an alternate implementation commented with uses Array.Copy() instead of a loop which would make for a better imlpementation.

Upvotes: 3

Related Questions