Cascading MouseMove Events

C

Crucifix

Hello,

I'm writing a small C# app, and part of what I'm trying to do
involves the dragging of PictureBox controls on a form. Unfortunately,
MouseMove seems to be behaving very oddly, causing spurious MouseMove
events when the cursor doesn't actually move. I've looked for a
solution in the groups, and although I've come close, I haven't found a
proper explanation or fix. Here is a rundown, followed by a very
simple test app that reproduces the issue:

The concept is simple. There's a PictureBox control, which is
subscribed to the MouseDown, MouseMove, and MouseUp events. The user
clicks (and holds) a PictureBox, which triggers the MouseDown event.
The event handler updates two private member variables which contain
(1) a reference to the PictureBox object, and (2) a Point struct
defining the location (origin) of the PictureBox object when it was
clicked.

The user then drags the control, and the MouseMove event is
triggered, which checks if the PictureBox reference is null - if it is,
it does nothing, if it is not, it offsets the location of the
PictureBox according to its origin, and the X/Y coordinates of the
mouse.

The MouseUp event simply sets the reference to the PictureBox to
null, so that no more MouseMove events are triggered, and the
PictureBox is left where it is.

When this app runs, and the user clicks and drags the PictureBox,
many MouseMove events are called - it seems that moving the PictureBox
triggers another MouseMove, but why? I've reduced the effect somewhat
by adding a check in MouseMove to see if the cursor position has
changed - this stops the cascading events, but it doesn't stop the
PictureBox control from drawing itself at two different locations
(flickering) as I move it around. (I'm sure double-buffering would fix
that, but I'd like to address the real problem).

Your help is much appreciated!



using System;
using System.Drawing;
using System.Windows.Forms;

namespace MouseMoveTest
{
public class MouseMoveTest : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox tomatoBox;
private System.Windows.Forms.PictureBox tomatoBox_Dragging;
private Point tomatoBox_Origin;

private Point mouseLocation = new Point(0,0);

private System.ComponentModel.Container components = null;

public MouseMoveTest()
{
this.SuspendLayout();

this.Name = "MouseMove Test Form";
this.Text = this.Name;
this.ClientSize = new System.Drawing.Size(512, 512);

this.tomatoBox = new System.Windows.Forms.PictureBox();
this.tomatoBox.BackColor = System.Drawing.Color.Tomato;
this.tomatoBox.Location = new System.Drawing.Point(160, 144);
this.tomatoBox.Name = "tomatoBox";
this.tomatoBox.Size = new System.Drawing.Size(64, 64);
this.tomatoBox.TabIndex = 0;
this.tomatoBox.TabStop = false;
this.tomatoBox.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseUp);
this.tomatoBox.MouseMove += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseMove);
this.tomatoBox.MouseDown += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseDown);

this.Controls.Add(this.tomatoBox);

this.ResumeLayout(false);
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

[STAThread]
static void Main()
{
Application.Run( new MouseMoveTest() );
}


private void tomatoBox_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseUp: " + e.X + "," + e.Y );

tomatoBox_Dragging = null;
}

private void tomatoBox_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseDown: " + e.X + "," + e.Y );

tomatoBox_Dragging = (sender as PictureBox );
tomatoBox_Origin = new Point( tomatoBox.Location.X,
tomatoBox.Location.Y );

Console.WriteLine( "Origin is: " + tomatoBox_Origin );
}

private void tomatoBox_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseMove: " + e.X + "," + e.Y );

// Only proceed if mouse position has changed.
/*
if ( mouseLocation.Equals(Cursor.Position) )
return;
else
mouseLocation = Cursor.Position;
*/

if ( tomatoBox_Dragging != null )
{
tomatoBox_Dragging.Left = tomatoBox_Origin.X + e.X;
tomatoBox_Dragging.Top = tomatoBox_Origin.X + e.Y;
}
}
}
}
 
M

Michael C

Crucifix said:
Hello,

I'm writing a small C# app, and part of what I'm trying to do
involves the dragging of PictureBox controls on a form. Unfortunately,
MouseMove seems to be behaving very oddly, causing spurious MouseMove
events when the cursor doesn't actually move. I've looked for a
solution in the groups, and although I've come close, I haven't found a
proper explanation or fix. Here is a rundown, followed by a very
simple test app that reproduces the issue:

Put this code back in and it works perfectly. You need to store the point
that the mouse clicked on the picturebox, not the original location of the
picturebox. And you should use Location instead of Left and Top so that it
is only moved once.
tomatoBox_Origin = new Point( e.X, e.Y );

if ( tomatoBox_Dragging != null )

{

tomatoBox_Dragging.Location = new Point(tomatoBox_Dragging.Left + e.X -
tomatoBox_Origin.X, tomatoBox_Dragging.Top +e.Y - tomatoBox_Origin.Y);

}



Michael

The concept is simple. There's a PictureBox control, which is
subscribed to the MouseDown, MouseMove, and MouseUp events. The user
clicks (and holds) a PictureBox, which triggers the MouseDown event.
The event handler updates two private member variables which contain
(1) a reference to the PictureBox object, and (2) a Point struct
defining the location (origin) of the PictureBox object when it was
clicked.

The user then drags the control, and the MouseMove event is
triggered, which checks if the PictureBox reference is null - if it is,
it does nothing, if it is not, it offsets the location of the
PictureBox according to its origin, and the X/Y coordinates of the
mouse.

The MouseUp event simply sets the reference to the PictureBox to
null, so that no more MouseMove events are triggered, and the
PictureBox is left where it is.

When this app runs, and the user clicks and drags the PictureBox,
many MouseMove events are called - it seems that moving the PictureBox
triggers another MouseMove, but why? I've reduced the effect somewhat
by adding a check in MouseMove to see if the cursor position has
changed - this stops the cascading events, but it doesn't stop the
PictureBox control from drawing itself at two different locations
(flickering) as I move it around. (I'm sure double-buffering would fix
that, but I'd like to address the real problem).

Your help is much appreciated!



using System;
using System.Drawing;
using System.Windows.Forms;

namespace MouseMoveTest
{
public class MouseMoveTest : System.Windows.Forms.Form
{
private System.Windows.Forms.PictureBox tomatoBox;
private System.Windows.Forms.PictureBox tomatoBox_Dragging;
private Point tomatoBox_Origin;

private Point mouseLocation = new Point(0,0);

private System.ComponentModel.Container components = null;

public MouseMoveTest()
{
this.SuspendLayout();

this.Name = "MouseMove Test Form";
this.Text = this.Name;
this.ClientSize = new System.Drawing.Size(512, 512);

this.tomatoBox = new System.Windows.Forms.PictureBox();
this.tomatoBox.BackColor = System.Drawing.Color.Tomato;
this.tomatoBox.Location = new System.Drawing.Point(160, 144);
this.tomatoBox.Name = "tomatoBox";
this.tomatoBox.Size = new System.Drawing.Size(64, 64);
this.tomatoBox.TabIndex = 0;
this.tomatoBox.TabStop = false;
this.tomatoBox.MouseUp += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseUp);
this.tomatoBox.MouseMove += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseMove);
this.tomatoBox.MouseDown += new
System.Windows.Forms.MouseEventHandler(this.tomatoBox_MouseDown);

this.Controls.Add(this.tomatoBox);

this.ResumeLayout(false);
}

protected override void Dispose( bool disposing )
{
if( disposing )
{
if (components != null)
{
components.Dispose();
}
}
base.Dispose( disposing );
}

[STAThread]
static void Main()
{
Application.Run( new MouseMoveTest() );
}


private void tomatoBox_MouseUp(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseUp: " + e.X + "," + e.Y );

tomatoBox_Dragging = null;
}

private void tomatoBox_MouseDown(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseDown: " + e.X + "," + e.Y );

tomatoBox_Dragging = (sender as PictureBox );
tomatoBox_Origin = new Point( tomatoBox.Location.X,
tomatoBox.Location.Y );

Console.WriteLine( "Origin is: " + tomatoBox_Origin );
}

private void tomatoBox_MouseMove(object sender,
System.Windows.Forms.MouseEventArgs e)
{
Console.WriteLine( "MouseMove: " + e.X + "," + e.Y );

// Only proceed if mouse position has changed.
/*
if ( mouseLocation.Equals(Cursor.Position) )
return;
else
mouseLocation = Cursor.Position;
*/

if ( tomatoBox_Dragging != null )
{
tomatoBox_Dragging.Left = tomatoBox_Origin.X + e.X;
tomatoBox_Dragging.Top = tomatoBox_Origin.X + e.Y;
}
}
}
}
 
C

Crucifix

Michael,

The code you responded with works perfectly! The effective
difference between your code and mine is that the new location of the
object is calculated differently (if I calculate the origin
incorrectly, it still works, just the image starts out in the wrong
place).

I'm really interested to know why setting the new location
(incorrectly) caused this problem. Do you (or does anyone else
reading) know why this is? I would have assumed that it would just put
my object in the wrong place... not result in cascading events.

Thank-you very much for your time Michael.

-David
 
M

Michael C

Crucifix said:
I'm really interested to know why setting the new location
(incorrectly) caused this problem. Do you (or does anyone else
reading) know why this is? I would have assumed that it would just put
my object in the wrong place... not result in cascading events.

Moving the control under the mouse will cause a mouse move event I believe,
so it's very easy to get the events firing repeatedly if your code isn't
moving the control to the correct location. I think you'll still get the
event firing repeatedly with the changes I made but the second time it fires
it will move the control to the same location so won't fire a third time.
Thank-you very much for your time Michael.

No worries, it took about 5 minutes as I worked on this exact problem about
a week ago :)

Michael
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top