-1

I'm making a graphical editor, but I am experiencing some problems with the drag & drop over a Panel. The Ellipse doesn't take the exact position where I drop it, and I think it's placed in a UserControl of size 150;150. Here's a link of a short movie to illustrate what I mean: http://gyazo.com/abf5484a31e2d1ce8ebccc49bee9fdb6 In the first part you can see that the Ellipse goes to the wrong position and in the end of the movie when I draw a line it seems that the ellipse has a block around it. How can I solve this issues?

Form1.cs

public partial class Form1 : Form
{
    bool draw = false;
    int x, y, xe, ye;

    public Form1()
    {
        InitializeComponent();

        menuComboBoxShape.ComboBox.DataSource = Enum.GetValues(typeof(Item));
    }

    public enum Item
    {
        Pencil,
        Rectangle, 
        Ellipse,
    }


    private void panel_MouseDown(object sender, MouseEventArgs e)
    {
        draw = true;
        x = e.X;
        y = e.Y;
    }

    private void panel_MouseUp(object sender, MouseEventArgs e)
    {
        draw = false;
        xe = e.X;
        ye = e.Y;

        Item item; 
        Enum.TryParse<Item>(menuComboBoxShape.ComboBox.SelectedValue.ToString(), out item);

        switch (item)
        {

            case Item.Pencil:
                using (Graphics g = panel.CreateGraphics())
                    using (var pen = new Pen(System.Drawing.Color.Black))     //Create the pen used to draw the line (using statement makes sure the pen is disposed)
                    {
                        g.DrawLine(pen,new Point(x, y), new Point(xe, ye));
                    }
                break;
            case Item.Rectangle:
                RectangleShape recShape = new RectangleShape(x, y, xe - x, ye - y);
                panel.Controls.Add(recShape);
                panel.Invalidate();
                break;
            case Item.Ellipse:
                EllipseShapeTest test = new EllipseShapeTest(x, y, xe - x, ye - y);
                panel.Controls.Add(test);
                panel.Invalidate();
                break;
            default:
                break;
        }
    }
}

EllipseShapeTest.cs

class EllipseShapeTest : UserControl
{
    private int x;
    private int y;
    private int width;
    private int height;

    public EllipseShapeTest(int x, int y, int width, int height)
    {
        setY(y);
        setX(x);
        setWidth(width);
        setHeight(height);
    }

    public int getX() { return x;}
    public int getY() { return y; }
    public int getWidth() { return width; }
    public int getHeight() { return height; }
    public void setX(int newx) { x = newx; }
    public void setY(int newy) { y = newy; }
    public void setWidth(int newwidth) { width = newwidth; }
    public void setHeight(int newheight) { height = newheight; }


    protected override void OnPaint(PaintEventArgs e)
    {
        base.OnPaint(e);
        // Call methods of the System.Drawing.Graphics object.

        // Draw an aqua rectangle in the rectangle represented by the control.
        e.Graphics.DrawEllipse(Pens.Aqua,x,y,width,height);
    }

    protected override void OnMouseMove(MouseEventArgs e)
    {

        // Make the cursor the Hand cursor when the mouse moves  
        // over the button.
        Cursor = Cursors.Hand;

        // Call MyBase.OnMouseMove to activate the delegate. 
        base.OnMouseMove(e);

        if (e.Button == MouseButtons.Left)
        {
            this.Location = new Point(e.X, e.Y);
            Invalidate();
        }
     }
TaW
  • 53,122
  • 8
  • 69
  • 111
Sybren
  • 1,071
  • 3
  • 17
  • 51
  • `this.Location` is relative to the UC's Parent but `e.Location` is relative to the UC surface. It usually works best to track the difference from the mouseDown point. – TaW May 15 '15 at 08:53
  • How would I do that in this case? Also the UC is always 150 by 150, doesn't this cause the positioning issues? – Sybren May 15 '15 at 09:02
  • The size doesn't matter; but as you can 'grab' the UC at any spot you need to use that spot to track the distance moved. See my answer for a very simple example (4 lines) and also for a discussion of the limitations of using controls as graphic shapes..! – TaW May 15 '15 at 09:30

1 Answers1

1

Here is a Label subclass that is draggable. The same code should work with any control, including your UserControl.

 public DragLabel()
 {
     //..
     MouseDown += DragLabel_MouseDown;
     MouseMove += DragLabel_MouseMove;
 }

 Point mDown { get; set; }

 void DragLabel_MouseDown(object sender, MouseEventArgs e)
 {
      mDown = e.Location;
 }

 void DragLabel_MouseMove(object sender, MouseEventArgs e)
 {
      if (e.Button == MouseButtons.Left)
      {
           Location = new Point(e.X + Left - mDown.X, e.Y + Top - mDown.Y);
      }
 }

If your application needs to make several classes draggable, you could put the fuctionality in a DragController class and register those controls that need it there..

As for your second problem: In the example we see only one control. In this simple case it should do to make the UC's BackColor = Color.Transparent. But once you want to add more such shapes you will hit a wall and, I'm afraid, you will have to give up on such a design. See here for a discussion of the problems and my suggested solution..!

BTW: Using a Control to move around the active shape is fine, but all other shapes will have to be Drawn onto the background. (This makes more sense after you have fully understood the last paragraph ;-)

Community
  • 1
  • 1
TaW
  • 53,122
  • 8
  • 69
  • 111
  • The dragging works now, thanks. You said the size of the UC doesn't matter, but if draw a ellipse bigger than 150 by 150 only a part is drawn. I don't quite understand the last two lines of your answer. – Sybren May 15 '15 at 09:38
  • Of course the UC needs to be as large as the shape it shall display. You will understand those lines once you have hit the wall and studied the linked post(s), believe me.. If not, do come back, but I'd rather not write it all down again.. – TaW May 15 '15 at 09:44