I've build a simple program (so far) that has a large panel as the "WorkArea" of the program. I draw a grid onto it, have some functionality that snaps my cursor to closest point on the grid etc. I have a status bar on the bottom of the window which displays my current position on the panel. However, regardless of where I've scrolled to (let's say vertical bar is at 10% relative to top and horizontal is 25%) it displays my cursor position with regards to the actual window.
I have a OnMouseMove event that handles this:
private void WorkArea_MouseMove(object sender, MouseEventArgs e)
{
GridCursor = grid.GetSnapToPosition(new Point(e.X, e.Y));
toolStripStatusLabel1.Text = grid.GetSnapToPosition(new Point(e.X, e.Y)).ToString();
Refresh();
}
It works as I'd expect giving the points of the cursor, drawing it to the correct place, and so on. However, if I scroll out, I still get the same readings. I could be scrolled out half way on the vertical and horizontal scrollbars, put my cursor in the upper left-hand corner, and read a 0,0, when it should be something more like 5000,5000 (on a panel 10k by 10k).
How can one go about getting the absolute position within a panel with respect to its scrollbars?
You need to offset the location by the scroll position:
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
Point scrolledPoint = new Point( e.X - panel1.AutoScrollPosition.X,
e.Y - panel1.AutoScrollPosition.Y);
..
}
Note that the AutoScrollPosition values are negative..:
The X and Y coordinate values retrieved are negative if the control
has scrolled away from its starting position (0,0). When you set this
property, you must always assign positive X and Y values to set the
scroll position relative to the starting position. For example, if you
have a horizontal scroll bar and you set x and y to 200, you move the
scroll 200 pixels to the right; if you then set x and y to 100, the
scroll appears to jump the left by 100 pixels, because you are setting
it 100 pixels away from the starting position. In the first case,
AutoScrollPosition returns {-200, 0}; in the second case, it returns
{-100,0}.
WinForms:
The method Control.PointToClient lets you convert the mouse position relative to the control itself.
Point point = grid.PointToClient(new Point(e.X, e.Y))
WPF:
Using Mouse.GetPosition you can get the position of the mouse relative to a specific control:
Point position = Mouse.GetPosition(grid);
Related
I'm trying to create a graph editor using WinForms.
I have a picture box, whenever I click on it the program draws a vertex by creating a label about 15px in size where I store a string, the location, etc.
I can draw the edges by drawing lines from location to location, but I need other boxes to do this, I wonder if there is a way to do this purely by touch (with the mouse cursor).
I need some kind of object that if clicked will start an event that will draw an edge up to the vertex I click next. I considered adding little picture boxes instead of labels, but the labels are convenient for storing the name of the vertexes, also I think adding both a label and an other box in the same position may hide one of the objects.
You can get the x and y coordinate's of the mouse on a user controls click event.
I would store the coordinate's of the last point you clicked on outside of the mouse click event and then draw a line from the last point to the new point.
lastPoint = null;
private void userControl_MouseClick(object sender, MouseEventArgs e) {
if (e.Button == MouseButtons.Left)
{
Point newPoint = e.Location;
if(lastPoint != null)
{
drawLine(lastPoint, newPoint);
}
lastPoint = newPoint;
}
}
Hope this helps.
I'm using Thumb to resize an element. On DragDelta I'm doing myElement.Width += e.HorizontalChange. What if I want to resize it by multiplier of 100?
I tried myElement.Width += 100 * e.HorizontalChange but it causes the element to "dance" when I drag it. I assume it happens because of the big change that causes wrong calculation of mouse position relative to the element.
How it can be done?
UPDATE
I recorded what I get. I resize the rectangle to the right and you can see how it flickering. The playback of the video is low but still you can see the flickering. It's much worse in reality.
It looks that Thumb computes the HorizontalChange relative to itself rather than to the screen. So, if the thumb itself does not move accurately with the mouse while dragging, then HorizontalChange takes unreliable values. (Another example of such unwanted behavior)
So, it seems that Thumb is of a little help when implementing custom move/resize behavior. A "manual" handling of mouse movement is needed. Though, we can still use Thumb's events as convenient points to handle the mouse.
FrameworkElement elementToResize;
double initialWidth;
Point initialMouse;
private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
{
initialWidth = elementToResize.ActualWidth;
initialMouse = Mouse.GetPosition(Window.GetWindow((DependencyObject)sender));
}
private void Thumb_DragDelta(object sender, DragDeltaEventArgs e)
{
var horzChange = Mouse.GetPosition(Window.GetWindow((DependencyObject)sender)).X - initialMouse.X;
elementToResize.Width = initialWidth + 100 * Math.Round(horzChange / 100);
}
We need to compute mouse position change in the screen coordinates. This is not straightforward in WPF. Assuming that window is not moving on the screen while dragging the thumb, getting mouse position relative to the window will suit, as in the above code. For better reliability, you can get actual mouse screen coordinates, but this requires conversion from pixels to WPF device independent units.
I have a custom control which consists of a Panel and a smaller pictureBox. When I DrawLine from Left,Top to Right,Bottom in the pictureBox, the starting point does not start in the corner of the pictureBox, and is offset +x and +y. If I expand the pictureBox to take up the entire size of the Panel, it lines up correctly. What's going on?
The pictureBox is Anchored to Top, Bottom, Left, and Right. No Docking.
private void pictureBoxPlot_Paint(object sender, PaintEventArgs e)
{
base.OnPaint(e);
e.Graphics.DrawLine(Pens.LightGray,
pictureBoxPlot.Left, pictureBoxPlot.Top,
pictureBoxPlot.Right, pictureBoxPlot.Bottom);
pictureBoxPlot.Invalidate();
}
Controls have their own coordinate system starting at (0, 0), so draw it like that:
e.Graphics.DrawLine(Pens.LightGray,
0, 0, pictureBoxPlot.ClientSize.Width, pictureBoxPlit.ClientSize.Height);
The pictureBoxPlot.Invalidate() should be removed since that would cause it to recursively call itself. Also, the base.OnPaint(e) looks out of place since you didn't override the paint method.
I believe the coordinates are relative to the picture box. If you want upper left, and a full line, use something like: 0, 0, pictureBoxPlot.height, pictureBoxPlot.Width
Draw is relative to your canvas. You are are attempting to draw where the actual location of the box resides on the form. Use PictureBoxPlot.ClientSize
I am trying to move shapes around on a canvas using the ManipulationDelta. It works but I am having an issue keeping them on my Canvas and by extension on the screen. I was trying to somehow determine the bounds of my canvas and whether its X, Y is still on the canvas. For instance, I was able to keep the Ellipse from being dragged off the top by setting Y to 0 when it is less than 0.
void Shape1_ManipulationDelta(object sender, ManipulationDeltaRoutedEventArgs e)
{
Ellipse shape = sender as Ellipse;
TranslateTransform tt = shape.RenderTransform as TranslateTransform;
tt.X += e.Delta.Translation.X;
tt.Y += e.Delta.Translation.Y;
if (tt.Y < 0)
tt.Y = 0;
}
The problem is that resolutions for screens differ and I can't figure out to determine the boundaries. Is this right approach to take or is there a better way to allow users to drag items but keep them inside a defined area?
Thanks for any help you can give me!
If the Canvas is the same size as the screen (aka Window), then you can inspect Window.Current.Bounds for the size of the Window.
I'm asking a question here cause I'm not sure how to search it in google, I don't know the word how to call this.
What I mean is a "zero point" which basically located at upper-left corner of the element, pictureBox for an example. So when I set new width and height properties for my pictureBox it works fine but it's relative to top left corner.
What I mean is you've got pictureBox, let's say 100 x 100 and you desire decrease it to 50 x 100, so you will get "empty space" under your picture box, not upper. PictureBox counts it's properties from this one top left corner zero point.
And what I need is to change this point to the another corner.
So when I change my height it count up, not down. Help me please.
I really hope you can understand me.
Wow, thank you guys for your advices! I've tested anchor property and Top += 50; now, doesn't solve my problem. Let me try to describe it another way. You have an image (100px) with grass 50px at bottom and sky 50px at the top. So you have picturebox with height 100. If you set pictureBox.height = 50; you will see only sky. But I need to leave only grass. The main problem I see here is because this zero point at top left corner.
Here is an example:
Button1 click event:
private void button1_Click(object sender, EventArgs e)
{
pictureBox1.Height = 150;
}
The result which you will get after you press the button:
But I need another result:
As I understand it happens because height property counts from the top left corner. So if I change it to bottom left or right corner it will works the way I need. Help me please to change this point...
MSDN reference: http://msdn.microsoft.com/en-us/library/system.windows.forms.picturebox.sizemode(v=vs.71).aspx
Valid values for this property are taken from the PictureBoxSizeMode enumeration. By default, in PictureBoxSizeMode.Normal mode, the Image is placed in the upper left corner of the PictureBox, and any part of the image too big for the PictureBox is clipped. Using the PictureBoxSizeMode.StretchImage value causes the image to stretch to fit the PictureBox.
Unless you are using a container which handles control layout automatically, you will have to move it yourself. I assume you are resizing the control in code with a line like:
myPictureBox.Height = 50;
You will have to also move the control's location down by the same amount:
myPictureBox.Top += 50;
Generalizing, something like this ought to do the trick for resizing height:
void ResizeHeightFromBottom(this Control c, int newHeight)
{
var oldBottom = c.Bottom;
c.Height = newHeight;
c.Top = oldBottom - newHeight;
}
I will leave resizing the width and both simultaneously as an exercise for the reader, as well as specifying an arbitrary reference point.