0

I am drawing rectangles or ellipses (depends on what is chosen) on a form using the Graphics object. Is there any way one can manipulate these graphical objects after they've been drawn? I mean actions such as resizing, deleting, dragging etc. Also, worth mentioning is the fact that there can be multiple shapes drawn on the same form and that they can overlap.

Drawing itself looks like this, triggered by the ScrollableControl's OnPaint() event - simply passing these methods a PaintEventArgs's Graphics object.

protected override void Fill(System.Drawing.Graphics g, Brush b)
{
    g.FillEllipse(b, m_topLeft.X, m_topLeft.Y, m_width, m_height);
}

protected override void Draw(System.Drawing.Graphics g, Pen p)
{
    g.DrawEllipse(p, m_topLeft.X, m_topLeft.Y, m_width, m_height);
}

I'd like to be able to click on a shape, choose what to do with it and act accordingly. I was thinking maybe I could check whether the cursor's position is within bounds of the shape (m_topLeft, m_width and m_height data members) and go from there. That doesn't take care of the potential overlapping though, even if it did work. There would be two (or more) shapes to which the selected point could belong to.

This is an example of two overlapping shapes (a rectangle and an ellipse) drawn using the user-defined parameters:

Example

Venom
  • 1,107
  • 4
  • 21
  • 46
  • 1
    It's certainly possible, but you'll have to code everything from scratch. This is not a trivial task. First develop a class to represent the shape and give it a way to draw itself in a selected state with drag handles. Then you'll need to do hit testing to see if the cursor is over those handles and act accordingly. For multiple shape hits you could give the user a way to select the next hit by pressing a key? – Idle_Mind Dec 01 '14 at 03:39
  • Alternatively, you might want to stop using deprecated winforms and move on to current technology, see [my example](http://stackoverflow.com/a/15580293/643085) – Federico Berasategui Dec 01 '14 at 18:08

1 Answers1

1

No, there is no way to minipulate the objects on screen after they have been drawn. What you need to do is have a list of all the objects that need to be drawn on screen and whenever you want to add, remove, or manipulate a object in that list you need to re-draw the entire list. You typically do this by calling Invalidate() on the control, that will call Draw to get called again which will normally itterate in a foreach loop over a collection of objects you want drawn.

public YourControl : Control
{
    List<IDrawableObject> _itemsToDraw = new List<IDrawableObject>();

    protected override void Draw(System.Drawing.Graphics g, Pen p)
    {
        foreach(var item in _itemsToDraw)
        {
            item.Draw(g, p);
        }
    }

    protected override void OnMouseClick(MouseEventArgs e)
    {
         base.OnMouseClick(e);

         IDrawableObject clickedItem = _itemsToDraw.FirstOrDefault(x=> x.WasClicked(e.Location));

         if(clickedItem != null)
         {
             //Do something with the clicked item.
         }
    }
}

interface IDrawableObject
{
    void Draw(System.Drawing.Graphics g, Pen p);

    bool WasClicked(Point p)
}

private class Ellipse : IDrawableObject
{    
    Point m_topleft;
    int m_width;
    int m_height;

    //Snip stuff like constructors assigning the values to the private fields.

    public void Draw(System.Drawing.Graphics g, Pen p)
    {
        g.DrawEllipse(p, m_topLeft.X, m_topLeft.Y, m_width, m_height);
    }

    public bool WasClicked(Point p)
    {
         return p.X >= m_topLeft.X && p.X < m_topLeft.X + m_width 
             && p.Y >= m_topLeft.Y && p.Y < m_topLeft.Y + m_height;
    }
}

For finding which control was clicked you can make a method like WasClicked that takes in the XY of the mouse at the time of the click and returns a true or false. You then can manipulate that object in the collection that returned true from the WasClicked function.

Scott Chamberlain
  • 124,994
  • 33
  • 282
  • 431
  • I am aware of that but how do I select a shape within that list which I'm already using to keep track of drawn shapes (just not their graphical representations)? – Venom Dec 01 '14 at 03:30
  • Thank you, I've just done the exact same thing with my code and it works as expected for rectangles but doesn't for ellipses since those have "blank" spots. I hope you understand what I meant. Only criteria left that I can think of is the color used to draw a shape. – Venom Dec 01 '14 at 03:46
  • I would ask a new question showing what you did and what results you are getting. – Scott Chamberlain Dec 01 '14 at 04:16