1

I am making an app where I have to draw things on a panel. I made a list of "Ellipsis" and draw the Ellipsis to a panel.

Lets say I have 10 Ellipsis drawn on the panel and I want to delete the 5th. How do I do that?

For each ellipse I made a rectangle behind it so that I can click on it.

I know there is a method called: "list1.RemoveAt()". The problem here is that I don't know the index of the list. How do I find the index of an ellipse when clicking on it?

Or shouldn't I use list1.removeAt()?

this is the code:

private void panelUseCase_MouseClick(object sender, MouseEventArgs e)
{
    x = e.X;
    y = e.Y;
    else if (rbUseCases.Checked && radioTest.Checked)
    {
        foreach (UseCase usecase in usecases)
        {

            if (x >= usecase.Field.Left && x <= usecase.Field.Right && y >= usecase.Field.Top && y <= usecase.Field.Bottom)
            {
                int bla = usecases.IndexOf(usecase);
                drawuc.RemoveAt(bla);
                panelUseCase.Invalidate();
            }
        }
    }
}

The variable usecase is in this case an ellipse. It's the last if statement from my panelUseCase_MouseClick method. As you can see, I have drawuc.RemoveAt(). Yet I have to put an index between (). But I don't know the index and I want to get the index by clicking on a usecase. Someone got an Idea?

Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
Alegou20
  • 60
  • 7
  • If you only test for a Rectangle why not use `ellips.Contains(Point)`? For proper ellipse testing you can use a GraphicsPath.IsVisible. See [here for a similar example](http://stackoverflow.com/questions/32919918/how-to-draw-line-and-select-it-in-panel/32920894?s=2|0.2144#32920894) - It is not recommended, infact often forbidden, to modify the collection you enumerate! A reverse for-loop is the recommended way, as in the below answer.. - Also: The code snippet is a little too short; we don't see where the x,y values come from. Show the whle event! – TaW Feb 22 '17 at 15:52
  • Why should I use ellips.contrains(point)? I am already checking if the rectangle is behind the ellipse. I don't need another "checking"thing.. And that was too complicated with the lines and stuff – Alegou20 Feb 22 '17 at 16:04
  • I have edited the whole event! – Alegou20 Feb 22 '17 at 16:15

1 Answers1

0

How do I find the index of an ellipse when clicking on it?

that would be using your if clause in the FindIndex method:

int index = usecases.FindIndex(el =>
            x >= el.Field.Left && 
            x <= el.Field.Right && 
            y >= el.Field.Top && 
            y <= el.Field.Bottom
            );

to delete the element you have to set it to null. Then you can remove it from you collection and invalidate your panel.

if (index >= 0)
{
    usecases[index] = null;
    usecases.RemoveAt(index);

    panelUseCase.Invalidate();
}

Here is a small program that draws ellipses on a panel by mouse click and deletes them when the CheckBoxDelete is checked. I tried to fit the names to the updated code of yours. This is a small example stripped down to the essentials that (I think) you asked for. You can copy paste, compile and run it into a WinForms project with a panel named panelUseCase and a checkbox named checkBoxDelete. Just add the 2 events and you are ready to go.

public partial class Form1 : Form
{
    public Form1()
    {
        InitializeComponent();
    }

    List<UseCase> usecases = new List<UseCase>();
    int x, y;
    UseCase _usecase;

    private void panelUseCase_MouseClick(object sender, MouseEventArgs e)
    {
        x = e.X;
        y = e.Y;

        if (checkBoxDelete.Checked && usecases.Any())
        {
            int index = usecases.FindIndex(el =>
            x >= el.Field.Left && 
            x <= el.Field.Right && 
            y >= el.Field.Top && 
            y <= el.Field.Bottom
            );

            if (index >= 0)
            {
                usecases[index] = null;
                usecases.RemoveAt(index);

                panelUseCase.Invalidate();
            }
        }
        else
        {
            if (!String.IsNullOrWhiteSpace(textBoxUseCaseName.Text)) // if name is typed into textbox
            {
                _usecase = new UseCase()
                {
                    Name = textBoxUseCaseName.Text,
                    X = x,
                    Y = y,
                    Field = new Rectangle(x, y, 40, 40)
                };

                usecases.Add(_usecase);

                panelUseCase.Invalidate();
            }
            else
            {
                MessageBox.Show("Need a Name for Usecase!");
            }
        }
    }

    private void panelUseCase_Paint(object sender, PaintEventArgs e)
    {
        Graphics g = panelUseCase.CreateGraphics();
        Pen p = new Pen(Color.Red);

        foreach (var el in usecases)
        {
            g.DrawEllipse(p, el.Field);
        }
    }
}

I guess you can fit that solution to accommodate for your problem. I hope this helps.

ps. This is the UseCase class implementation that I used:

public class UseCase
{
    public string Name { get; set; }
    public Point MyPoint { get; set; }
    public Rectangle Field { get; set; }
    public int X { get; set; }
    public int Y { get; set; }

    public UseCase()
    {
        MyPoint = new Point();
        Field = new Rectangle();
    }      
}
Mong Zhu
  • 23,309
  • 10
  • 44
  • 76
  • I don't get your code? you have a foreach combined with a forloop? – Alegou20 Feb 22 '17 at 15:40
  • It's not working, When I press the ellipse to delete it. It's not doing anything. It look likes it's only refreshing the page. But the ellipse it not going away. with that for loop – Alegou20 Feb 22 '17 at 15:46
  • The code you dropped its not working, its not deleting anything :(, anyone else have another idea? – Alegou20 Feb 22 '17 at 22:29
  • @Alegou20 I have posted a working code for drawing and deleting elipses by mouse click. I tried to adjust it to the names of your updated code. Have a look – Mong Zhu Feb 23 '17 at 09:01
  • First of all thankyou for your help. But the code you posted is not robust. It's working when You click 2/3 times. But when you draw 20 ellipsis and you want to delete them the application is crashing.. It gives this error: "The index is out of range. These must not be negative and must be smaller than the size of the collection." – Alegou20 Feb 23 '17 at 10:17
  • @ MongZhu, I posted the code where I draw my ellipses. But I guess the code is too long for this question. I think it's good to look at your "small program" to see if it works. If it works there. I can implement that in my own code. Yet, the code you posted is crashing when I create alot of ellipses and want to delete it. I am running into this problem for a while now, tried different things but the error is not going away.. – Alegou20 Feb 23 '17 at 10:23
  • @Alegou20 thanx for pointing it out. I forgot to check whether an elipsed has been hit correctly with the mouse and a valid index came out. Fixed that – Mong Zhu Feb 23 '17 at 10:24
  • @Alegou20 the crash is not due to many ellipses but due to not hitting an ellipse with the mouse. The index is out of range because `FindIndex` will return -1 if the coordinate condition is not met by any element in the list. – Mong Zhu Feb 23 '17 at 10:26
  • @ Mong Zhu, thank your for your help. Your code is working perfectly now. When I put that in my own application it is still crashing now. I am going to find the error. Thanks for your help!! – Alegou20 Feb 23 '17 at 10:33
  • @Alegou20 you are welcome. I wish you success. If my answer helped you, you might consider to mark my answer as accepted. Have a nice day – Mong Zhu Feb 23 '17 at 11:01
  • I did accept your asnwer. But because I don't have 15+ rep you cant see it – Alegou20 Feb 23 '17 at 11:13
  • I have 1 more question, is it possible to add a string to the list of usecases? Now I am only adding a _usecase. When I try to add a string to the list of usecases. It says: "Usecase does not takes a contrusctor with 2 arguments". I tried the following" usecases.Add(new UseCase(_usecase,_usecase.Name));" instead of: usecases.Add(_usecase); When I go to the usecase class and put (string name) in the constructor it won't work because it needs a constructor with 2 overloads. (let's use your little program as example) – Alegou20 Feb 23 '17 at 11:35
  • @Alegou20 If you pass the entire object `_usecase` to the contsructor of `UseCase` you will already have the value of `_usecase.Name`. So it is unnecessary information. Why do you want to add the additional string `Name` ? – Mong Zhu Feb 23 '17 at 11:45
  • I need to put a string in the ellips. But it's not showing a string because I never add a string to the list: This is the code for painting. foreach (var el in usecases) { graphics.DrawEllipse(PenBlack, el.Field); graphics.DrawString(el.Name, this.Font, Brushes.Black, el.Positie.X - 30, el.Positie.Y - 10); } – Alegou20 Feb 23 '17 at 11:51
  • You seem never to assign anything to `_usecase.Name` in your `MouseClick` event where you create a new instance. You need to assign a value to it when you create it, like the `Field` or the coordinates. I guess you just forgot to do that. – Mong Zhu Feb 23 '17 at 11:56
  • Correct, I indeed never asign anything to _usecase.Name. I fixed it! thanks! – Alegou20 Feb 23 '17 at 11:57
  • @Alegou20 I added it to my answer. Now it gets really advanced ;) – Mong Zhu Feb 23 '17 at 12:03
  • I guess I accepted it now. Sorry I clicked on the upper arrow instead of the thing under it – Alegou20 Feb 23 '17 at 13:29