I am implementing an application which can be drag and drop images in a panel and so I want to make sure that the image is placed within the panel and it is visible the whole image when is dropped.In that case I want to get the current cursor position when I doing drag and drop event. So how can I get the cursor location related to panel?
Here is the method of panel dragdrop event.
private void panel1_DragDrop(object sender, DragEventArgs e)
{
Control c = e.Data.GetData(e.Data.GetFormats()[0]) as Control;
if (c != null)
{
if (e.X < 429 && e.X > 0 && e.Y<430 && e.Y>0)
{
c.Location = this.panel1.PointToClient((new Point(e.X, e.Y)));**
this.panel1.Controls.Add(c);
}
}
}
You can get cursor coordinates using Cursor.Position, this gets you screen coordinates. you can then pass these into PointToClient(Point p)
Point screenCoords = Cursor.Position;
Point controlRelatedCoords = this.panel1.PointToClient(screenCoords);
Though, I am fairly certain that DragEventArgs.X and DragEventArgs.Y are already screen coordinates. Your problem probably lies in
if (e.X < 429 && e.X > 0 && e.Y<430 && e.Y>0)
This looks like it would be checking against Panel coordinates, whereas e.X and e.Y are screen coordinates at that point. Instead, thansform it into panel coords before checking against bounds :
Point screenCoords = Cursor.Position;
Point controlRelatedCoords = this.panel1.PointToClient(screenCoords);
if (controlRelatedCoords.X < 429 && controlRelatedCoords.X > 0 &&
controlRelatedCoords.Y < 430 && controlRelatedCoords.Y > 0)
{
}
Related
I'm defining shapes which inherit from class Shape and implement the 'Geometry' property.
Here's an example:
public class Landmark : Shape
{
public override bool IsInBounds(Point currentLocation)
{
return (((currentLocation.X >= Location.X - 3) && (currentLocation.X <= Location.X + 3)) && ((currentLocation.Y >= Location.Y - 3) && (currentLocation.Y <= Location.Y + 3)));
}
protected override Geometry DefiningGeometry
{
get
{
var landMark = new EllipseGeometry {Center = Location};
Stroke = Brushes.Red;
return landMark;
}
}
protected override void OnIsMouseDirectlyOverChanged(DependencyPropertyChangedEventArgs e)
{
StrokeThickness = IsMouseDirectlyOver ? 12 : 6;
Mouse.OverrideCursor = IsMouseDirectlyOver ? Mouse.OverrideCursor = Cursors.ScrollAll : Mouse.OverrideCursor = Cursors.Arrow;
}
protected override void OnMouseMove(MouseEventArgs e)
{
if (e.LeftButton == MouseButtonState.Pressed)
{
Location = e.GetPosition(this);
InvalidateVisual();
}
}
}
When I click on the Shape and move my mouse, I expect the Shape to be redrawn in the new location - and it does work.
However, if I move the mouse "too" quickly, then I'm "leaving" the OnMouseMove event, and the shape gets stuck in the last position which the mouse pointer and the Shape's location were in "sync".
Can such issue be solved?
Yes, by capturing the Mouse.
For that to work you must establish when to capture and when to release. Since you want this to work with the left mouse button, you can capture in OnMouseDown and release the mouse in OnMouseUp.
I have a richtextbox. When I'm holding control and spin the scroll wheel, the text size is changing.
But how do I get the text size after changing it by ctrl + scroll? RichTextBox1.Font.Size is always 8.25.
Google did not help.
What you're looking for is the ZoomFactor of RichTextBox:
Gets or sets the current zoom level of the RichTextBox.
That's why you don't see the font size change.
Use this code:
private void richTextBox1_KeyDown(object sender, KeyEventArgs e)
{
float zoom = richTextBox1.ZoomFactor;
if ((zoom * 2 < 64) && (zoom / 2 > 0.015625))
{
if (e.KeyCode == Keys.Add && e.Control)
{
richTextBox1.ZoomFactor = zoom * 2;
}
if (e.KeyCode == Keys.Subtract && e.Control)
{
richTextBox1.ZoomFactor = zoom / 2;
}
}
}
So I have a PictureBox and the user is supposed to drag the cursor inside it towards the direction shown by the arrow (in the PictureBox), but I'm not sure how I will set the coordinates to make sure the user dragged in the correct direction (up, down, right, or left).
private void picArrow_MouseDown(object sender, MouseEventArgs e)
{
mPointDown = new Point(e.X, e.Y);
//lblTest.Text = "X: " + mPointDown.X.ToString() + " Y: " + mPointDown.Y.ToString();
}
private void picArrow_MouseUp(object sender, MouseEventArgs e)
{
lblTest.Text += " " + " X: " + e.X.ToString() + " Y: " + e.Y.ToString();
//MessageBox.Show("Entered mouseup");
//rnd_Arr refers to the number of the arrow being shown, 0 = towards the right
if (rnd_Arr == 0 && mPointDown.X >= 0 && mPointDown.Y >= 0 && e.X >= 40 && e.Y >= 0)
{
//some code
}
else
{
MessageBox.Show("DONE!");
}
}
And I know this code doesn't work because even if the user drags down (when he's supposed to drag up), it still accepts it and increments the score.
I'm not putting too much restrictions. It doesn't have to be in a perfectly straight line, or start and end in exact locations. As long as the user is dragging inside the PictureBox and dragging to the correct direction, or at least reaches the minimum length to make sure it is considerable that the user is dragging to the correct direction, like for example:
The arrow shown is pointing to the right. The user doesn't have to drag all the way through the arrow, if he drags horizontally past 40px (and the whole length of the arrow is, say, 80px), then that'll add a point to his score. Nevertheless, I'm deliberating this part, if I should just be more demanding and require the user to drag all the way through.
Should I remove the mouse events for the PictureBox and add mouse events for the form instead?
Thank you!
You're going to want to check the MouseDown.X and compare it to the MouseUp.X (or Y if you want to check vertical direction as well). It is important to note that (0, 0) is the upper left of your screen.
Start by subtracting MouseUp.X from MouseDown.X to get a delta X. This is your change in X pixels over the move operation.
If your X comparison yields a negative delta (MouseUp.X is smaller than MouseDown.X), your mouse has moved left.
If your X comparison yields a positive delta (MouseUp.X is larger than MouseDown.X), your mouse has moved right.
The same concept applies to the Y coord, positive change means you moved the mouse down and a negative changemeans you moved the mouse up. See below code:
Point mouseDownPoint;
Point mouseUpPoint;
float deltaX = mouseUpPoint.X - mouseDownPoint.X;
float deltaY = mouseUpPoint.Y - mouseDownPoint.Y;
if (deltaX > 0)
{
// Moved right
}
else if (deltaX < 0)
{
// Moved left
}
if (deltaY > 0)
{
// Moved down
}
else if (deltaY < 0)
{
// Moved up
}
private void picArrow_MouseUp(object sender, MouseEventArgs e)
{
bool movedUp, movedDown, movedLeft, movedRight;
if (e.X == mPointDown.X) { movedRight = movedLeft = false; }
else { movedRight = e.X < mPointDown.X; movedLeft = !movedRight; }
if (e.Y == mPointDown.Y) { movedUp = movedDown = false; }
else { movedUp = e.Y < mPointDown.Y; movedDown = !movedUp; }
// Code can now use the Booleans above as needed
// . . .
}
i have taken one Flow layout panel and placed multiple picture box inside in it. now i want when i will place my mouse at the right or left most edge of the Flow layout panel then rest of picture will scroll out. just think about windows 8 start screen where many tiles appear in screen and when we place mouse at right most edge on the screen then rest of the tiles scroll out. i want to simulate same thing in windows form with Flow layout panel.
i want my Flow layout panel will not show scroll bar but images will scroll out when i will place mouse right or left most part on the panel. here is my screen shot
some one told me to do it this way...here is bit code
Set AutoScrollPosition property in MouseMove event of Panel.
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
panel1.AutoScrollPosition = new Point(e.X, e.Y);
}
but this trick was not good. AutoScrollPosition works when scroll bar is visible but in my case i do not want to show scroll bar with Flow layout panel. i want smooth scrolling images from left to right or right to left. anyone can help me to achieve what i am trying to do....if possible guide me with respect of coding. thanks
EDIT
Here i am giving my full code after modification following #Taw suggestion but it is not working fine....rather flickering found when picture move. anyway here is the full code.
namespace ScrollTest
{
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
flowLayoutPanel1.MouseMove += MouseScroll;
foreach (Control x in this.Controls)
{
if (x is PictureBox)
{
((PictureBox)x).MouseMove += MouseScroll;
}
}
}
int near = 33;
private void MouseScroll(object sender, MouseEventArgs e)
{
Point mouse = flowLayoutPanel1.PointToClient(MousePosition);
Rectangle C = flowLayoutPanel1.ClientRectangle;
int dLeft = mouse.X - C.Left;
int dTop = mouse.Y - C.Top;
int dRight = C.Right - mouse.X;
int dBottom = C.Bottom - mouse.Y;
int dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
int dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;
if (dX != 0 | dY != 0) scrollFLP(dX, dY);
}
void scrollFLP(int deltaX, int deltaY)
{
flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
System.Threading.Thread.Sleep(11);
}
int getSpeedFromDistance(int delta)
{
int sig = Math.Sign(delta);
int d = Math.Abs(delta);
if (d > near / 2) return sig;
else if (d > near / 3) return near / 10 * sig;
else if (d > near / 4) return near / 8 * sig;
else if (d > near / 5) return near / 5 * sig;
else return near * sig;
}
}
}
basically i am trying achieve something like suppose i have flow layout panel and which has many picture box inside it with many images as the screen shot but scroll bar should not show rather scroll will happen automatically when i will place my mouse at the top or bottom of the flow layout panel like carousel.
see this picture of your application
when place my mouse at the right end then it scroll and form background shown which i do not want. i want picture box will scroll & scroll upto last one not more than that.
any idea how to do it. thanks
2nd Edit
this code i added as per your suggestion
public Form1()
{
InitializeComponent();
for (int i = 0; i < 666; i++)
{
PictureBox pan = new PictureBox();
//pan.MouseMove += MouseScroll;
//pan.MouseLeave += outSideCheck;
pan.Size = new Size(75, 75);
pan.BackColor = Color.FromArgb(255, (i * 2) & 255, (i * 7) & 255, (i * 4) & 255);
flowLayoutPanel1.Controls.Add(pan);
}
//flowLayoutPanel1.MouseMove += MouseScroll;
//this.flowLayoutPanel1.MouseLeave += outSideCheck;
mouseScroller MSC = new mouseScroller();
MSC.registerControl(flowLayoutPanel1); // FLP = your FlowLayouPanel
MSC.timerSpeed = 5; // optional
MSC.nearness = 100; // optional
flowLayoutPanel1.AutoScroll = false;
}
now the apps doing wired behavior after adding new code. if i am making any mistake then guide me please. thanks
This is a two-part problem:
How to grab the event
How to scroll a FlowLayoutPanel with its scrollbars invisible.
Second first. It is not an easy task from what I found, unless you use a simple and rather common trick: Don't actually scroll it! Instead place it into a Panel and then control its position inside that Panel.
To do this you add a Panel panel1 to your Form, Dock or Anchor it as you need to and set its Autoscroll = false (!) (Which is not the way it is usually done, when you want to make, say a PictureBox scrollable. But we don't want the Panel to show it Scrollbars either.)
Set the FLP to its desired size and place it into the Panel, it obviously also has Autoscroll = false, and we're ready to tackle the other problem of setting up the event..:
First you add the MouseScroll event below to your code and then you hook every control up to it you want to work with the mouse move, namely the FLP:
flowLayoutPanel1.MouseMove += MouseScroll;
..and also each of your PictureBoxes, maybe like this
// your creation loop..
PictureBox pbox = new PictureBox();
pbox.MouseMove += MouseScroll; // <<--- hook into to the mousemove
pan.MouseLeave += outSideCheck; // <<--- hook into to the mouseleave
// .. do your stuff.. here I put some paint on to test..
pbox.BackColor = Color.FromArgb(255, 111, (i * 3) & 255, (i * 4) & 255);
flowLayoutPanel1.Controls.Add(pbox);
or however you create them..
Edit 2 I have changed my original code once more. It now includes an outside check, a check for moving towards the closest edge and a workaround for tha mousemove bug. It uses a Timer set to maybe 30ms. The speed mapping is in a function of its own.
flowLayoutPanel1.MouseMove += MouseScroll;
this.flowLayoutPanel1.MouseLeave += outSideCheck;
flowLayoutPanel1.AutoScroll = false;
int near = 33;
Point lastLocation = Point.Empty;
int dX = 0;
int dY = 0;
private void MouseScroll(object sender, MouseEventArgs e)
{
Point mouse = panel1.PointToClient(MousePosition);
Rectangle C = panel1.ClientRectangle;
// mouseMove has a bug, we need to workaround
if (mouse == lastLocation) return;
if (lastLocation == Point.Empty) { lastLocation = mouse; return; }
// distance from each edge
int dLeft = mouse.X - C.Left;
int dTop = mouse.Y - C.Top;
int dRight = C.Right - mouse.X;
int dBottom = C.Bottom - mouse.Y;
// relevant distances with sign
dX = dLeft < near ? dLeft : dRight < near ? -dRight : 0;
dY = dTop < near ? dTop : dBottom < near ? -dBottom : 0;
// we need the closest edge to check if we are moving in or out
List<int> edges = new List<int>() { dLeft, dTop, dRight, dBottom };
var closest = edges.IndexOf(edges.Min());
// if we are moving
if (dX != 0 | dY != 0)
// if moving out: go else stop going
if (!movingIn(mouse, closest)) timer1.Start(); else timer1.Stop();
// remember position
lastLocation = mouse;
}
bool movingIn(Point current, int Edge)
{
switch (Edge)
{
case 0: return current.X > lastLocation.X;
case 1: return current.Y > lastLocation.Y;
case 2: return current.X < lastLocation.X;
case 3: return current.Y < lastLocation.Y;
}
return false;
}
void scrollFLP(int deltaX, int deltaY)
{
flowLayoutPanel1.Left += getSpeedFromDistance(deltaX);
flowLayoutPanel1.Top += getSpeedFromDistance(deltaY);
Size C = panel1.ClientSize;
if (flowLayoutPanel1.Left > 1) { flowLayoutPanel1.Left = 0; timer1.Stop(); }
if (flowLayoutPanel1.Right < C.Width)
{ flowLayoutPanel1.Left = C.Width - flowLayoutPanel1.Width; timer1.Stop(); }
if (flowLayoutPanel1.Top > 1) { flowLayoutPanel1.Top = 0; timer1.Stop(); }
if (flowLayoutPanel1.Bottom < C.Height)
{ flowLayoutPanel1.Top = C.Height - flowLayoutPanel1.Height; timer1.Stop(); }
}
int getSpeedFromDistance(int delta)
{
int sig = Math.Sign(delta);
int d = Math.Abs(delta);
if (d > near / 2) return sig;
else if (d > near / 3) return 2 * sig;
else if (d > near / 4) return 4 * sig;
else if (d > near / 5) return 6 * sig;
else return 10 * sig;
}
private void timer1_Tick(object sender, EventArgs e)
{
if (insidePanel()) scrollFLP(dX, dY); else timer1.Stop();
}
bool insidePanel()
{
return panel1.ClientRectangle.Contains(panel1.PointToClient(MousePosition));
}
private void outSideCheck(object sender, EventArgs e)
{
if (!insidePanel()) {timer1.Stop(); lastLocation = Point.Empty;}
}
Of course you'll want to play with the various 'magic' numbers :-)
Stop code and direction check are now included.
As usual, key is to know precisely what you want.. I hope this gets you started on ways to achieve it!
It's been a while since this question was asked. I just encountered the problem. My scenario was a little different, but I still think it's a solution to the same problem (at worst a timer control can be used because autoscroll is not turned on).
Here is my scenario: I have one panel control (normal panel). I have an PictureBox in it that I made with zoom. I'm making rectangular selections on top of this image, and when the selections spilled out of the panel, my panel was supposed to slide in the direction I was selecting. (in my scenario, mouse is pressed)(also in my scenario, autoscroll is on). This is how I solved it without writing so much code:
I added two private variable for scroll position (Valid for the whole class scope).
private int xPos;
private int yPos;
private int speed = 5;
and I assigned them the current scroll positions when the form is loaded.
private void Form1_Load(object sender, EventArgs e)
{
//when I change the scrollbar manually or change with zoom I still
//need to add these lines to the related event
xPos = panel1.HorizontalScroll.Value;
yPos = panel1.VerticalScroll.Value;
}
and inside my picturebox's mousemove event
private void picturebox1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left) {
Point mouse = panel1.PointToClient(MousePosition);
if (!panel1.ClientRectangle.Contains( mouse ))
{
Rectangle CRect = panel1.ClientRectangle;
int dLeft = mouse.X - CRect.Left;
int dRight = CRect.Right - mouse.X;
int dTop = mouse.Y - CRect.Top;
int dBottom = CRect.Bottom - mouse.Y;
if(dLeft < 0 && panel1.HorizontalScroll.Value > 0)
{
xPos = -panel1.AutoScrollPosition.X - speed;
}
if (dRight < 0 && panel1.HorizontalScroll.Value < panel1.HorizontalScroll.Maximum)
{
xPos = -panel1.AutoScrollPosition.X + speed;
}
if (dTop < 0 && panel1.VerticalScroll.Value > 0)
{
yPos = -panel1.AutoScrollPosition.Y - speed;
}
if (dBottom < 0 && panel1.VerticalScroll.Value < panel1.VerticalScroll.Maximum)
{
yPos = -panel1.AutoScrollPosition.Y + speed;
}
panel1.AutoScrollPosition = new Point(xPos, yPos);
}
}
}
void Rectangle_ManipulationDelta(object sender, ManipulationDeltaEventArgs e)
{
//(0/-897)(0/-135)
// Move the rectangle.
Thickness mapmar = MapCont.Margin;
Current.Text = mapmar.Left+"_"+mapmar.Top;
if (marginThickness.Left < 0)
{
MapCont.Margin = new Thickness(0,0,0,0);
}
move.X += e.DeltaManipulation.Translation.X;
move.Y += e.DeltaManipulation.Translation.Y;
}
The idea is that the Canvas is Really big for the view so i use the DeltaMaipulation to allow the user to scroll around it, i need to keep track of the margins to force some clipping
i tried printing the values of the margins (textfield) it's 0 0 no matter what
thanks for your help
The ManipulationDelta Doesn't use the Margin property to position the elements
alternative code:-
use the TranslateTransform Object
private TranslateTransform move = new TranslateTransform();
use the X and Y attributes to do the clipping or any related thing
if (move.X < 0)
{
move.X = 0;
}