Reputation: 1047
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:
Upvotes: 0
Views: 829
Reputation: 127543
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.
Upvotes: 1