0

I've been trying to make a drag and drop game. I have 4 panels and 4 labels. You have to drag the labels on top of the correct panel.

The problem is checking if a label is on top of the panel. The user can frely drag the labels.

private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            button1.Left = e.X + button1.Left - MouseDownLocation.X;
            button1.Top = e.Y + button1.Top - MouseDownLocation.Y;
        }
    }

    private void button1_MouseDown(object sender, MouseEventArgs e)
    {
        if (e.Button == System.Windows.Forms.MouseButtons.Left)
        {
            MouseDownLocation = e.Location;
        }
    }

Here is the code i used to move the control. I have to mention that this is a test project, so I used a button instead of a label, but the idea is the same.

Is there any way if I can check whether a control is on top of another or not ?

ChJ16
  • 51
  • 1
  • 9
  • Possible duplicate of [How to get control under mouse cursor?](https://stackoverflow.com/questions/2411062/how-to-get-control-under-mouse-cursor) – Markus Feb 15 '19 at 16:46
  • when do you consider the label to be on top of the panel ? When its complete over the panel or just a little part ? – GuidoG Feb 15 '19 at 16:46
  • 1
    Wouldn't the control you're moving always be the one on top? – LarsTech Feb 15 '19 at 16:53

2 Answers2

1

To check if the mouse is over the control, you can check if the Cursor.Position is in the ClientRectangle of the control, but you first need to call PointToClient method of the control to convert the cursor position relative to the panel's (0,0), for example:

var b = panel1.ClientRectangle.Contains(panel1.PointToClient(Cursor.Position));

The flag can be checked in the same event handler which is used to move the control, for example:

if(b) panel1.BackColor = Color.Red; else panel1.BackColor = Color.Gray;
Reza Aghaei
  • 120,393
  • 18
  • 203
  • 398
  • It seems you forgot to mention when/where this condition should be checked :) Since the OP is not really dragging an object but instead moving a Control around, other Controls won't raise MouseEnter/MouseMove events when the Cursor is over their client area (IIRC). – Jimi Feb 15 '19 at 17:31
  • @Jimi No other control event handler is needed; The flag can be checked in the same event handler which is used by the OP to move the control. Something like `if(b) panel1.BackColor = Color.Red; else panel1.BackColor = Color.Gray;`. – Reza Aghaei Feb 15 '19 at 17:46
  • Yes, sure. But this doesn't determine the relation between the moving object ant the *Right Container*. Suppose you have 10 Labels (instead of 4) that you have to move inside 10 different Panels and you have to determine whether the Label is inside the *Right* Panel. Also, suppose that what makes a Panel the *Right One* is a random condition (i.e., a Word (text) that needs to be coupled with another). If the *Right Panel* for `Label1` is always `Panel1`... – Jimi Feb 15 '19 at 18:13
  • @Jimi Assuming we have a really complex function like `Panel GetPanel(Label)` which returns the right panel for a label then the question is again simplified to *check if mouse is over a specific control*. Then above code just need `var panel1 = GetPanel((Label)sender);` before `var b = ...`. Right? – Reza Aghaei Feb 15 '19 at 18:20
  • That would be perfect! :) (Maybe, using the Controls Tags to set a correponding value). – Jimi Feb 15 '19 at 18:28
  • Checking if the **cursor** is within the panel isn't quite right. For example, if you grab the button by the left side, then drag it to the right...the button will be over the panel while the cursor is still on the outside! – Idle_Mind Feb 15 '19 at 20:03
  • @Idle_Mind I see, but it depends to the expectations. Imagining a cross cursor while dragging the control, my expectation is highlighting the panel, when the cursor is over the panel. – Reza Aghaei Feb 15 '19 at 20:22
  • 1
    Also since there is a chance the controls are not hosted in the same container, for example labels are on a group box and panels are in another group box, I'd check intersection or containing this way: `var b = panel1.Parent.RectangleToScreen(panel1.Bounds).IntersectsWith(label1.Parent.RectangleToScreen(label1.Bounds));` – Reza Aghaei Feb 15 '19 at 20:25
  • But, IMO, these are all implementation details. When you have a distinct source and a distinct destination (all Control that participate in the *deal* are known), you can offset the location of the Cursor in the middle of the source, if you want to. Or define a *sensible area* of the source that intersects with the destination area. – Jimi Feb 15 '19 at 20:31
1

After each move, simply get the Rectangle from the Bounds property of your button and panel, then use either Intersect() or Contains():

    private void button1_MouseMove(object sender, MouseEventArgs e)
    {
        if (e.Button == MouseButtons.Left)
        {
            button1.Location = new Point(e.X + button1.Left - MouseDownLocation.X, e.Y + button1.Top - MouseDownLocation.Y);
            Rectangle btnRC = button1.Bounds;
            Rectangle pnlRC = panel1.Bounds;

            // see if the rectangles INTERSECT
            if (pnlRC.IntersectsWith(btnRC))
            {
                panel1.BackColor = Color.Green;
            }
            else
            {
                panel1.BackColor = this.BackColor;
            }

            // see if the panel COMPLETELY CONTAINS the button
            if (pnlRC.Contains(btnRC))
            {
                panel1.BackColor = Color.Green;
            }
            else
            {
                panel1.BackColor = this.BackColor;
            }
        }
    }
Idle_Mind
  • 38,363
  • 3
  • 29
  • 40
  • Just so you're aware, this code assumes that both controls being compared are in the same **container**. If they are not, you could convert the coordinates to screen coords and then do the comparison. – Idle_Mind Feb 20 '19 at 18:38