I've just made some simple code to track the mouse offset from where Mouse Down to its current position on Mouse Move within a PictureBox. I'm outputting the difference to a label and it works fine.
So say I mousedown at X: 20 Y: 20 then move mouse left by 5. My result is X: 15 Y:20.
Now the issue is when I take these results (diffX and diffY) and add them to an integer (testOne and testTwo). The result is exponentially different.
Most relevant is that when I keep the mouse in the same position without moving it but just holding the button. The results continue to increase.
I have reduced my problem to the following code:
Point startPoint = new Point();
bool dragging = false;
int testOne = 30;
int testTwo = 30;
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
if (dragging)
{
int diffX = (pictureBox1.PointToClient(e.Location).X - startPoint.X);
int diffY = (pictureBox1.PointToClient(e.Location).Y - startPoint.Y);
label9.Text = diffX.ToString(); //Works, shows desired result
label10.Text = diffY.ToString(); //also works fine
testOne = (testOne + diffX); //Issue here
testTwo = (testTwo + diffY); //and here
label11.Text = (testOne).ToString(); //Unexpected results output
label12.Text = (testTwo).ToString();
}
}
private void pictureBox1_MouseDown(object sender, MouseEventArgs e)
{
if (!dragging) //Incase the mouse down was repeating, it's not
{
startPoint = pictureBox1.PointToClient(e.Location);
dragging = true;
}
}
private void pictureBox1_MouseUp(object sender, MouseEventArgs e)
{
if (dragging)
dragging = false;
}
I'm using C# WinForms in VS 2008, Framework 3.5
any insight would be great, maybe this is a bug or I've simply overlooked something simple. Any ideas or if you can re-produce.
Cheers
Craig
It looks as though you are subtracting the current point from the start point, not the last point. Set startPoint to the current point at the end of your mousemove function.
startPoint = pictureBox1.PointToClient(e.Location);
Whe you don't move mouse you should not be getting MouseMove events... Also clicking mouse button will send you MouseMove. In genral MouseMove is send whenever it seems practical and you should be ready to handle 0 movements too.
The value of testOne and testTwo measures "Sum of all mouse movements" which will grow as long as mouse offset (diffX/Y) is positive (essentially it is integral of mose movements). What your expectations for this values?
Related
I am making an application in which I load a bunch of 256x256px chunks of a map and stitch them together with magick.net to then display them in a picture box. I added a feature for slewing the image (and loading new picture chunks as I do) using mouse events on the picture box control like so:
// Set true when mouse should slew the picture in the picture box
private bool isSlewing = false;
// last position of the mouse in map space when slewing
private float lastX = 0;
private float lastY = 0;
private void Pb_MouseMove(object sender, MouseEventArgs e)
{
// slew while mouse is down.
if (isSlewing)
{
Tuple<float, float> mouseMapCoordinates = MouseToMap(e.X, e.Y);
Slew(mouseMapCoordinates.Item1 - lastX, mouseMapCoordinates.Item2 - lastY);
lastX = mouseMapCoordinates.Item1;
lastY = mouseMapCoordinates.Item2;
}
}
private void Pb_MouseDown(object sender, MouseEventArgs e)
{
isSlewing = true;
Tuple<float, float> mouseMapCoordinates = MouseToMap(e.X, e.Y);
lastX = mouseMapCoordinates.Item1;
lastY = mouseMapCoordinates.Item2;
}
private void Pb_MouseUp(object sender, MouseEventArgs e)
{
isSlewing = false;
}
// Slews map image by dx and dY
public void Slew(float dX, float dY)
{
X -= dX;
Y -= dY;
}
// Converts mouse coordinates into map coordinates
private Tuple<float,float> MouseToMap(int mouseX, int mouseY)
{
// works
}
X and Y are properties that invalidate the picture box by setting a boolean needsUpdate to true. A timer is run and every 200ms it calls the update function which builds the picture based on X and Y . There also is a zoom but that's unimportant for now and works fine.
The issue is that when I click and drag the map it works in principle but every so often the map "jumps" back to a previous mouse position.
I just don't know how to go about trying to find out what's causing it or how to fix it.
I would like the whole program to be a bit more responsive to begin with, it feels sluggish, which is why I introduced the timer to begin with, so it doesn't draw updates on every little change dozens of times per second as I move the mouse a tiny amount.
I think it has to do with some kind of race condition that sets lastX and lastY between one slew and the next with the update drawing things in between. The update function takes a few milliseconds to complete, as it loads the images from disk and composites them and finally draws them back to the picture box.
The whole code is available at github. Map data is not included, but can be downloaded with the script in Assets. For testing I recommend deleting all but one map from the json file there. All map data in total is about 3GB.
I tried putting lock() around the block inside the if statement in Pb_MouseMove, but that didn't help anything.
The issue was with converting the mouse coordinates into map space outside of slew because the map space moves with the viewport. To fix the issue you save the raw mouse position in lastX and lastY, put the raw delta for the mouse coordinate into the slew function and then multiply by a scaling factor. The scaling factor is how many map coordinate units are used per pixel.
I have a PictureBox that loads me a web page, I need to be able to place the mouse or cursor at certain coordinates within the PictureBox. However, I can't do it, use several ways to get the coordinates but once the web page loads, it doesn't work.
private void m_WebView_MouseClick(object sender, MouseEventArgs e)
{
label1.Text = "X = " + e.X + " ; Y = " + e.Y;
}
private void m_WebView_MouseMove(object sender, MouseEventArgs e)
{
label1.Text = e.Location.X.ToString();
label1.Text = e.Location.Y.ToString();
}
does not work when loading the web page and event is set
If I leave the picture box empty, if it shows me the coordinates
I need to locate the mouse in the exact coordinates that I see
Is it possible?
that its i try coords not work
var simulator = new InputSimulator();
Point position = PointToScreen(pictureBox1.Location) +
new Size(pictureBox1.Location.X / 2 , pictureBox1.Location.Y / 7 );
SetCursorPos(position.X, position.Y);
for #Olivier Jacot-Descombes
works the question is how do I locate the coordinates of a and b without having to adjust the values of
e.Width / 2, pictureBox1.Size.Height / 7));
and start the program close edit open close edit, until I manage to locate them that is my main problem
with this I get coordinates but they don't work
private void m_WebView_MouseMove (object sender, MouseEventArgs e)
{
label1.Text = e.Location.X.ToString ();
label2.Text = e.Location.Y.ToString ();
}
point A = x 106 and Y 106
point B = x 564 and y 225
How do I put those coordinates since they don't work
To place the cursor inside the picture, you must add a fraction of Size.Width and Size.Height to the location of the picture box.
This works for me
Cursor.Position = pictureBox1.PointToScreen(
new Point(pictureBox1.Size.Width / 2, pictureBox1.Size.Height / 7));
Note that this uses the PointToScreen method of the picture box instead of the form. Therefore, the location of the picture box is used as a reference automatically. This save us some calculations.
So I'm trying to make a slider. I'm using my cursor to move a button's x position.
I have 3 functions, the mouseDown, mouseUp and the mouseMove function. In the mouseUp and mouseDown functions I set a variable to true and false to tell the program that the mouse is clicked or not. In the mouseMove function I tell the program to set the button's x position to the x position of the mouse when the mouse is clicked. This works but has 2 problems.
The first problem is that when I press the button and move it, the button moves along with the mouse's x but it has a space between the mouse and the button. It looks a bit like this:
CURSOR.......BUTTON
The space between the cursor and button change when I change the resolution of the form.
The second problem is that when I move the button it flickers a bit. It only does this at higher speeds but it is a problem in my case.
My code looks like this:
bool mouseDown = false;
private void volumeGrabBT_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = true;
}
}
private void volumeGrabBT_MouseUp(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
mouseDown = false;
}
}
private void volumeGrabBT_MouseMove(object sender, MouseEventArgs e)
{
if (mouseDown == true)
{
Point volumeBTPoint = new Point();
volumeBTPoint.X = Cursor.Position.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
}
}
The volumeGrabBT is the button I'm trying to move along with the mouse.
The volumeBTPoint is the point of the button I'm trying to set the button's position to.
I hope someone can help me fix these problems. Thanks in advance!
I believe that flickering can be fixed by setting some additional form styles: SetStyle(ControlStyles.AllPaintingInWmPaint |ControlStyles.UserPaint | ControlStyles.DoubleBuffer, true);
in form's constructor. It will use double buffering and generally just draws faster.
For the Cursor class, it's relative to the screen, not your form. You can use this.PointToClient() function to get client's space position of cursor, like this:
Point clientCursor = this.PointToClient(Cursor.Position);
and then use clientCursor to get exact X in your client space.
You have to translate screen coordinates to client coordinates.
Point volumeBTPoint = new Point();
Point point = this.PointToClient(Cursor.Position);
volumeBTPoint.X = point.X;
volumeBTPoint.Y = volumeGrabBT.Location.Y;
volumeGrabBT.Location = volumeBTPoint;
Instead of this you should use button's parent control (Panel, GroupBox, etc).
I have a draggable element in a StackPanel in a Windows 8 store app. My goal is simple: drag the item somewhere on the screen and immediately after the user stops dragging it the element should return to its original starting position.
I have the following code which is meant to accomplish this task:
private void grdCover_ManipulationCompleted(object sender, ManipulationCompletedRoutedEventArgs e)
{
Grid coverControl = sender as Grid;
double xOffset = -e.Cumulative.Translation.X;
double yOffset = -e.Cumulative.Translation.Y;
if (coverControl.RenderTransform is TranslateTransform)
{
TranslateTransform existingTransform = coverControl.RenderTransform as TranslateTransform;
existingTransform.X += xOffset;
existingTransform.Y += yOffset;
}
else
{
TranslateTransform transform = new TranslateTransform();
transform.X = xOffset;
transform.Y = yOffset;
coverControl.RenderTransform = transform;
}
}
The code sort of works. The screen looks like this upon application start:
The top element, which looks like a H is well aligned with the bottom element which looks like a U. When I first drag the H element it jumps back to its well aligned position, or at least any misalignment is so little that it's hardly perceivable to the naked eye. As I keep dragging and releasing the H element it gets more and more misaligned like this:
After 15-20 dragging moves the H element gets completely misplaced:
The problem might be due to some rounding error of the double values in the Point objects when they are translated into pixels, but that's only a wild guess. Also, on a high resolution device, such as my PC it takes more moves for the misalignment to become visible than on a lower resolution one, such as the Windows Simulator in Visual Studio.
Some other code that may be related to this issue:
I perform the dragging operation with the following code:
private void Grid_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
TranslateTransform translateTransform = (sender as Grid).RenderTransform as TranslateTransform;
translateTransform.X += e.Delta.Translation.X;
translateTransform.Y += e.Delta.Translation.Y;
}
I also have the following event handler in place to stop the element from moving too much on the screen after the user is done dragging the element:
private void grdCover_ManipulationInertiaStarting(object sender, ManipulationInertiaStartingRoutedEventArgs e)
{
e.TranslationBehavior.DesiredDeceleration = 10000000000000000;
e.Handled = true;
}
In case you're wondering I wanted to set the desired deceleration to Double.Max to block any further "sliding" movement on the screen but I got an exception saying it was out of bounds. So instead I chose this arbitrary large value.
I have no extra margins or padding on the layout root or the element to be moved or its container.
Any ideas are welcome.
Thanks, Andras
OK, I got it to work. The problem was that there was a slight mismatch between the Point coordinates in the following code bits:
TranslateTransform translateTransform = (sender as Grid).RenderTransform as TranslateTransform;
translateTransform.X += e.Delta.Translation.X;
translateTransform.Y += e.Delta.Translation.Y;
and
double xOffset = -e.Cumulative.Translation.X;
double yOffset = -e.Cumulative.Translation.Y;
The solution was to retrieve the value of
e.Delta.Translation.X
and
e.Delta.Translation.Y
and assign their values to the variables xOffset and yOffset. Retrieving the values of
e.Cumulative.Translation.X
and
e.Cumulative.Translation.Y
gave slightly different coordinates so the element kept jumping back to the wrong location.
I'm developing an app for windows mobile (Compact Framework 2.0). It has a WinForms with a PictureBox.
I want to move the image of the PictureBox but I don't know how to do it so I choose to move the hole PictureBox.
To do it I use this event:
private void imagenMapa_MouseMove(object sender, MouseEventArgs e)
{
imagenMapa.Left = e.X;
imagenMapa.Top = e.Y;
this.Refresh();
}
But when I move the PictureBox it blinks and moves every where.
What I'm doing wrong?
Actual Code (Requires .NET Framework 3.5 and beyond, not sure if this is available in the Compact Framework)...
// Global Variables
private int _xPos;
private int _yPos;
private bool _dragging;
// Register mouse events
pictureBox.MouseUp += (sender, args) =>
{
var c = sender as PictureBox;
if (null == c) return;
_dragging = false;
};
pictureBox.MouseDown += (sender, args) =>
{
if (args.Button != MouseButtons.Left) return;
_dragging = true;
_xPos = args.X;
_yPos = args.Y;
};
pictureBox.MouseMove += (sender, args) =>
{
var c = sender as PictureBox;
if (!_dragging || null == c) return;
c.Top = args.Y + c.Top - _yPos;
c.Left = args.X + c.Left - _xPos;
};
The e.X and e.Y are relative to the picture box (e.g. if the mouse is in the upper left of the picture box, that's 0,0) .
The values for imagenMapa.Left and imagenMapa.Top are relative to the form (or whatever control contains imagenMapa)
If you try to mix values from these two systems without conversion, you're going to get jumps (like you're seeing).
You're probably better off converting the mouse position to the same coordinate system used by the thing that contains the picture box.
You could use imagenMapa.PointToScreen to get the mouse coordinates in screen coordinates (or Cursor.Position to get the position directly), and yourForm.PointToClient to get them back in the form coordinates.
Note that depending on your needs, you could accomplish "moving an image within a control" by overriding/handling the Paint event of a control and drawing the image yourself. If you did this, you could keep everything in the picturebox coordinates, since those are likely what you would use when you called graphicsObject.DrawImage.
e.X & e.Y is in the coordinate space of the pictureBox, imagenMapa.Left & imagenMapa.Top is in the coordinate space of the Form. :-)
Also don't forget to set your form to double buffered, that might help with the flickering, but for the actual positioning of it, I like Daniel L's suggestion
Embrace math!
control.Left = control.Left - (_lastMousePos.X - currentMousePos.X);
control.Top = control.Top - (_lastMousePos.Y - currentMousePos.Y);
Quick explanation:
You get the difference from the mouse positions and apply it to the object you want to move.
Example:
If the old mouse X position is 382, and the new one is 385, then the difference is -3. If the controls current X position is 10 then 10 - (-3) = 13
Why:
It works for anything, and is much cheaper than constantly converting coordinates back and forth.
Actually what you have done is correct. But you gave the MouseMove property to the picturebox. You should give that property to the Form(background).
ex:
private void Form1_MouseMove(object sender, MouseEventArgs e)
{
imagenMapa.Left = e.X;
imagenMapa.Top = e.Y;
}