Get MouseWheel Scroll Position in a FlowLayoutPanel - c#

I have a FlowLayoutPanel which can be scrolled by the user on the verticle axis. i have the following event handler which is used to see where the user has scrolled to and provides the position number within blocks of 405px:
private void ChangedParentFlowPanel_Scroll(object sender, ScrollEventArgs e)
{
int NewPos = e.NewValue;
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
That works just fine and does exactly what i need when the user scrolls using the verticle bar. The problem i have is i need to update tCounter with the same value but this time when the user scrolls using the mouse wheel. I'Ve tried the following but this only ever seems to provide the Y axis value for the location of the mouse when it scrolls and not the location of the scroll itself:
private void ChangedParentFlowPanel_Wheel(object sender, MouseEventArgs e)
{
int NewPos = e.Location.Y;
MessageBox.Show(NewPos.ToString());
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
The question is...how can i get the scroll position of the scroll in ChangedParentFlowPanel when a mousewheel is used?

Thanks to the comment by Hans Pasant here's the answer:
private void ChangedParentFlowPanel_Wheel(object sender, MouseEventArgs e)
{
int NewPos = Math.Abs(ChangedParentFlowPanel.AutoScrollPosition.Y);
int range = (NewPos - 1) / 405 + 1;
CurrentIndex_Changed = range;
tCounter.Text = CurrentIndex_Changed.ToString();
}
Math.Abs because the returned scroll Y value is minus and i need a positive value.

Related

How to limit panning on the X Axis with ZedGraph?

A lot of people already asked this but I haven't found an answer that works for me. I just want to make the user unable to zoom out/pan outside a certain range (between 0 and "size" in my example below). I managed to limit the zooming by using the ZoomEvent and setting the Max and Min values manually, but I can't figure out how to do the same for panning. Here is a bit of code:
int size = 40000;
graphControl.ZoomEvent += GraphControl_ZoomEvent;
graphControl.Scroll += GraphControl_Scroll;
graphControl.ScrollEvent += GraphControl_Scroll;
private void GraphControl_Scroll(object sender, ScrollEventArgs e)
{
if (graphControl.MasterPane.PaneList[0].XAxis.Scale.Max > size)
graphControl.MasterPane.PaneList[0].XAxis.Scale.Max = size;
if (graphControl.MasterPane.PaneList[0].XAxis.Scale.Min < 0)
graphControl.MasterPane.PaneList[0].XAxis.Scale.Min = 0;
graphControl.MasterPane.AxisChange();
graphControl.Refresh();
}
private void GraphControl_ZoomEvent(ZedGraphControl sender, ZoomState oldState, ZoomState newState)
{
if (sender.MasterPane.PaneList[0].XAxis.Scale.Max > size)
sender.MasterPane.PaneList[0].XAxis.Scale.Max = size;
if (sender.MasterPane.PaneList[0].XAxis.Scale.Min < 0)
sender.MasterPane.PaneList[0].XAxis.Scale.Min = 0;
sender.MasterPane.AxisChange();
sender.Refresh();
}
The code above almost does it, but the Min and Max values update only after I've let go of my panning button, I want to limit it at all times (including during the panning). I also think it's worth mentioning that the Scroll event isn't firing at all.
Thank you in advance!
Subscribe to MouseMoveEvent and use the same code like in ZoomEvent.
Additionally, do this only if pan mouse button (middle) is pressed (or Ctrl and left mouse button). If you limit Min side, you have to set the Max side also to maintain the same axis span if you don't want to change the scale of the XAxis.
In this example below I limited only one side. Return false to allow the execution of other actions (panning).
double limit = 0;
double span;
private bool GraphControl_MouseMoveEvent(ZedGraphControl sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Middle || (e.Button == MouseButtons.Left && (ModifierKeys & Keys.Control) == Keys.Control))
{
span = graphControl.GraphPane.XAxis.Scale.Max - graphControl.GraphPane.XAxis.Scale.Min;
if (graphControl.GraphPane.XAxis.Scale.Min < limit)
{
graphControl.GraphPane.XAxis.Scale.Min = limit;
graphControl.GraphPane.XAxis.Scale.Max = limit + span;
}
}
return false;
}

ManipulationDeltaRoutedEventArgs.IsInertial always returning false

I'm developing a windows phone app and I want to estimate the distance for element when user flicks on screen. The problem is ManipulationDeltaRoutedEventArgs.IsInertial is always returning false and I'm unable to detect the user flick.
This is my ManipulationDelta Event Handler
private void ItemList_ManipulationDelta(Object sender, ManipulationDeltaRoutedEventArgs e)
{
double currPos = e.Position.X;
var fwElement = (FrameworkElement)sender;
Thickness margin = fwElement.Margin;
margin.Left += (currPos - origin);
if (margin.Left < marginLeft) margin.Left = marginLeft;
fwElement.Margin = margin;
if (e.IsInertial)
{
System.Diagnostics.Debug.WriteLine("intertial");
}
}
You need to have Inertia related ManipulationModes enabled for e.IsInertial to work.
For example,
this.ManipulationMode = ManipulationModes.TranslateX | ManipulationModes.TranslateInertia;

Moving Picturebox on a Grid is inaccurate because Mouse Positions are inaccurate

I have an Application where I put Pictureboxes on a Panel. After I successfully implemented Drag&Drop for the Pictureboxes, I wanted to add a Grid option to conviniently move the Pictureboxes on the Panel. The code I used is
private void PB14_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
if (grid)
{
if (MousePosition.X % 10 == 0)
{
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(MousePosition.X, MousePosition.Y)).X, PBList[14].Location.Y);
}
if (MousePosition.Y % 10 == 0)
{
PBList[14].Location = new Point(PBList[14].Location.X, PList[parent].PointToClient(new Point(MousePosition.X, MousePosition.Y)).Y);
}
}
else
{
...
}
}
}
PList is a List of Panels, PList[parent] is the parent in which the picturebox (out of a Pictureboxlist) PBList[14] is.
The Problem is that the Picturebox is not smoothely moving, sometimes it doesnt move at all. I found out that some values for the % operation are better some are worse, for example if I put
if (MousePosition.X % 30 == 0)
in the if statement, it is worse than 10.
I put the values of the if() in labels and i saw that it would sometimes skip the calculation, means the value jumped from 9 to 1, skipping the pixel where it should be 0 and the Picturebox didnt move.
Do you know any better ways of calculating the mouse coordinates for this purpose?
You'll want to determine the closest pixel of the grid pixels to your mouse position.
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(MousePosition.X - (MousePosition.X % 10) + 5, MousePosition.Y - (MousePosition.Y % 10) + 5)).X);
Although my confusion is setting in here about the required parameters for PointToClient.
The jist of it is, recalculate the position for each mouse move regardless of whether it is directly on your 'grid by 10s', assign the location if it is different from the last (to save resources on re-painting) and find the closest 'grid by 10s' position by subracting the co-ords remainder of 10 from the co-ord
The problem is you only move anything when the mouse is exactly over one of the grid points.
One way to do this is allowing an extra pixel on each side:
if ((MousePosition.X+1) % 30 < 3)
{
int newX = MousePosition.X + 1 - ((MousePosition.X+1) % 30);
PBList[14].Location = new Point(PList[parent].PointToClient(new Point(newX, MousePosition.Y)).X, PBList[14].Location.Y);
}
//Same for Y
I was able to add snap-to-grid behaviour to my typical drag-and-drop implementation. The grid is based on the Control's Height and Width. You can change this by replacing control.Height and control.Width with constants, if you prefer. You may also want to prevent the Control from being dragged off screen.
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
control.Left = ((e.X + control.Left) / control.Width) * control.Width;
control.Top = ((e.Y + control.Top) / control.Height) * control.Height;
}
}
If you want the Control to drag smoothly and only snap-to-grid when you release the mouse button instead:
private void OnMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
control.Left += e.X - offset.X;
control.Top += e.Y - offset.Y;
}
}
private void OnMouseUp(object sender, MouseEventArgs e)
{
control.Left = ((control.Left + control.Width / 2) / control.Width) * control.Width;
control.Top = ((control.Top + control.Height / 2) / control.Height) * control.Height;
}
private void OnMouseDown(object sender, MouseEventArgs e)
{
offset = e.Location;
}

winform move an image inside a picturebox

I've been trying to do this for a few hours now, but for the life of me I can't make it possible.
What I'm trying to do is simply move the image found within a picture box in a winform application. My image is roughly 1000x1000 pixels and my box is something arbitrary like 400x500, so, for example, when I click the mouse I'd want the image to move 50 to the left. But the image box should remain the same size.
For the life of me, however, I can't get this to work. What I have been able to do is the following:
if (kinectController.hands[0].fingertips.Count == 1)
{
pictureBox1.SizeMode = PictureBoxSizeMode.CenterImage;
}
This function is for my kinect finger tracking app. So when the application finds a single finder point visiable on the screen, the image is centered. However, I would eventually like the image to move along with my finger movement, which will come once I work out the basic step of moving the image a few pixels to the side.
Any help with this would be appreciated.
I did a little bit of research and apparently moving an image within a PictureBox is no easy task, at the very least I couldn't find anything that would make this possible (not saying there isn't a way to do it though).
However, I came up with a bit of a "workaround", see if this fits your needs. To accomplish this:
Create a Panel control, and size it to however much of the image you
would like to display
Inside that panel place a PictureBox control with your image in it
and set the SizeMode property to AutoSize.
Now, put this code in your form
private bool Dragging;
private int xPos;
private int yPos;
private void pictureBox1_MouseUp(object sender, MouseEventArgs e) { Dragging = false; }
private void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
Dragging = true;
xPos = e.X;
yPos = e.Y;
}
}
private void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
Control c = sender as Control;
if (Dragging && c!= null) {
c.Top = e.Y + c.Top - yPos;
c.Left = e.X + c.Left - xPos;
}
}
Now whenever you click and drag on the PictureBox, it won't actually move the image within it, but the PictureBox control within the panel. Again, not exactly what you were looking for and I'm not sure how this would convert over to Kinect, but I hope this gets you on the right track.
Not enough reputation to comment but I wanted to add on Ben Black answer if someone ever need more control over the image moving around so you can't move the image past it's borders :
private void pictureBox1_MouseMove(object sender, MouseEventArgs e)
{
Control c = sender as Control;
if (Dragging && c != null)
{
int maxX = pictureBox1.Size.Width * -1 + panel.Size.Width;
int maxY = pictureBox1.Size.Height * -1 + panel.Size.Height;
int newposLeft = e.X + c.Left - xPos;
int newposTop = e.Y + c.Top - yPos;
if (newposTop > 0)
{
newposTop = 0;
}
if (newposLeft > 0)
{
newposLeft = 0;
}
if (newposLeft < maxX)
{
newposLeft = maxX;
}
if (newposTop < maxY)
{
newposTop = maxY;
}
c.Top = newposTop;
c.Left = newposLeft;
}
}

Set autoscroll position on mouse move

I need to update scroll bar position when I click on image and move picturebox. It is always at the beggining, it only moving on the right side (horizontall) and down (vertical).
private void pictureBox1_MouseMove_1(object sender, MouseEventArgs e)
{
....
Point currentMousePos = e.Location;
int distanceX = currentMousePos.X - mouseX;
int distanceY = currentMousePos.Y - mouseY;
int newX = pictureBox1.Location.X + distanceX;
int newY = pictureBox1.Location.Y + distanceY;
if (newX + pictureBox1.Image.Width + 10 < pictureBox1.Image.Width && pictureBox1.Image.Width + newX + 10 > panel1.Width)
{
pictureBox1.Location = new Point(newX, pictureBox1.Location.Y);
}
if (newY + pictureBox1.Image.Height + 10 < pictureBox1.Image.Height && pictureBox1.Image.Height + newY + 10 > panel1.Height)
{
pictureBox1.Location = new Point(pictureBox1.Location.X, newY);
}
}
I think you need to change the AutoScrollPosition of the parent panel and not play around with the Location points of the PictureBox. After all, the scroll bars of the parent panel are already taking care of the position of the PictureBox.
Try something like this (by the way, my code only does this when a button is pressed, otherwise, I think it would be a weird user interface design):
private Point _StartPoint;
void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left)
_StartPoint = e.Location;
}
void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left) {
Point changePoint = new Point(e.Location.X - _StartPoint.X,
e.Location.Y - _StartPoint.Y);
panel1.AutoScrollPosition = new Point(-panel1.AutoScrollPosition.X - changePoint.X,
-panel1.AutoScrollPosition.Y - changePoint.Y);
}
}
LarsTech's code isn't 100% correct. 2 notes:
Note that if slider is moved, then the same point on screen changes it's coordinates relative to pictureBox1 (as pictureBox moved with moved slider). Therefore we want to use the screen coordinates (Control.MousePosition instead of e.Location).
Changing panel1.AutoScrollPosition causes the move of pictureBox relative to mouseCursor, so the pictureBox1.MouseMove event is fired again, even if cursor didn't move on the screen. Adding _StartPoint = Control.MousePosition prevents unwanted scrolling.

Categories