I am trying to get a control to follow the cursor when the user clicks and drag the control. The problem is that 1.) the control doesn't go to the mouse's position, and 2.) the control flickers and flies all over the place. I've tried a few different methods of doing this, but all so far have failed.
I've tried:
protected override void OnMouseDown(MouseEventArgs e)
{
while (e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Location = e.Location;
}
}
and
protected override void OnMouseMove(MouseEventArgs e)
{
while (e.Button == System.Windows.Forms.MouseButtons.Left)
{
this.Location = e.Location;
}
}
but neither of these work. Any help is appreciated, and thanks in advance!
Here's how to do it:
private Point _Offset = Point.Empty;
protected override void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_Offset = new Point(e.X, e.Y);
}
}
protected override void MouseMove(object sender, MouseEventArgs e)
{
if (_Offset != Point.Empty)
{
Point newlocation = this.Location;
newlocation.X += e.X - _Offset.X;
newlocation.Y += e.Y - _Offset.Y;
this.Location = newlocation;
}
}
protected override void MouseUp(object sender, MouseEventArgs e)
{
_Offset = Point.Empty;
}
_Offset is used here for two purposes: keeping track of where the mouse was on the control when you initially clicked it, and also keeping track of whether the mouse button is down or not (so that the control doesn't get dragged when the mouse cursor goes over it and the button isn't down).
You definitely don't want to switch the ifs in this code to whiles, as it will make a difference.
there are mistakes in the answer 1
1.Set mouse handlers to control ,not to form
like button1_MouseMove
2.do not use this vector,but your control instead(Point newlocation = button1.Location;)
3.you do not need to override handlers.
in my test after these changes button(or other control) moves fine.
Chigook
Try this to move the object according to the mouse's position and the code below given is to gather the mouse's move path and the location saved in the arraylist to obtain the path where mouse point is moving. You have to declare the arraylist globally.
private void panel1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ArrayList inList = new ArrayList();
inList.Add(e.X);
inList.Add(e.Y);
list.Add(inList);
}
}
When the user clicks the button the control has to move in the path that the user dragged in the screen
private void button1_Click_2(object sender, EventArgs e)
{
foreach (ArrayList li in list)
{
pic_trans.Visible = true;
pic_trans.Location = new Point(Convert.ToInt32(li[0]), Convert.ToInt32(li[1]));
pic_trans.Show();
}
}
private Point ptMouseDown=new Point();
protected override void MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
ptMouseDown = new Point(e.X, e.Y);
}
}
protected override void MouseMove(object sender, MouseEventArgs e)
{
if (_Offset != Point.Empty)
{
Pointf[] ptArr=new Pointf[]{this.Location};
Point Diff=new Point(e.X-ptMouseDown.X,e.Y-ptMouseDown.Y);
Matrix mat=new Matrix();
mat.Translate(Diff.X,Diff.Y);
mat.TransFromPoints(ptArr);
this.Location=ptArr[0];
}
}
protected override void MouseUp(object sender, MouseEventArgs e)
{
_Offset = Point.Empty;
}
Related
customBtn1 is the custom scrollbar. The below code sample works, but the scrolling action is jittery and stuttery. It does not scroll smoothly. Any idea why this could be happening and how to fix it?
int PreviousBarLoc;
private void MainForm_Load(object sender, EventArgs e)
{
PreviousBarLoc= customBtn1.Location.Y;
}
//move the scrollbar up and down when the user drags it
private void customBtn1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{ MouseDownLocation = e.Location; }
}
private Point MouseDownLocation;
private void customBtn1_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
customBtn1.Top = e.Y + customBtn1.Top - MouseDownLocation.Y;
}
}
//scroll the panel
private void customBtn1_LocationChanged(object sender, EventArgs e)
{
int locDifference = customBtn1.Location.Y - PreviousBarLoc;
if (steamSrvListPnl.VerticalScroll.Value + locDifference <= 255 && steamSrvListPnl.VerticalScroll.Value + locDifference >= 0)
{
steamSrvListPnl.VerticalScroll.Value += locDifference;
}
PreviousBarLoc= customBtn1.Location.Y;
}
Your deltas are not quite right. The way it is currently written, if you drag the mouse down and then start dragging back up, it will not scroll back up because your current e.Y is still below the original MouseDownLocation.Y. I'm not entirely sure of your setup, but below is an example of how to get smooth scrolling to work when the left mouse button is pressed and dragged on a button:
private int _prevY = 0;
private bool _mouseDown = false;
private void button1_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
_mouseDown = true;
_prevY = e.Y;
}
}
private void button1_MouseMove(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
panel1.VerticalScroll.Value = Math.Max(panel1.VerticalScroll.Minimum, Math.Min(panel1.VerticalScroll.Maximum, panel1.VerticalScroll.Value + e.Y - _prevY));
_prevY = e.Y;
}
}
private void button1_MouseUp(object sender, MouseEventArgs e)
{
if (_mouseDown)
{
_mouseDown = false;
_prevY = 0;
}
}
private void Brick_MouseDown(object sender, MouseEventArgs e)
{
isDragging = true;
}
private void Brick_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
Brick1.Left = e.X;
Brick1.Top = e.Y;
}
}
public void Brick_MouseUp(object sender, MouseEventArgs m)
{
isDragging = false;
}
It kinda works but it glitches out when you move it (The picturebox teleports around the screen rapidly). https://www.youtube.com/watch?v=hWazyAnGNBE
You need to use the PointToClient method of the Form
var relativePoint = this.PointToClient(new Point(X, Y));
// Or
var relativePoint = this.PointToClient(Cursor.Position);
Control.PointToClient Method (Point)
Computes the location of the specified screen point into client
coordinates.
Update
private void Brick_MouseMove(object sender, MouseEventArgs e)
{
if (isDragging)
{
var relativePoint = this.PointToClient(Cursor.Position);
Brick1.Left = relativePoint.X;
Brick1.Top = relativePoint.Y;
}
}
I got myself drag and drop functionality in my little card game. I want just like in the windows card games to be able to drag and drop my cards. Now, I simply tried to make the drag and drop, but it's acting weird. The card is a custom control called Card.
I first will explain it:
1. I hold my mouse button on the card
2. It moves to another location (without me moving the mouse).
3. The card now moves correctly, but when I release the mouse button, the card will be at that position, but it won't be the position of my mouse since it was off when I clicked.
This is my code:
public void CardMouseDown(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
cardClickInitLocation = ((Card)sender).Location;
}
}
public void CardMouseUp(object sender, MouseEventArgs e)
{
}
public void CardMouseMove(object sender, MouseEventArgs e)
{
if (e.Button == System.Windows.Forms.MouseButtons.Left)
{
((Card)sender).Left = e.X + ((Card)sender).Left - cardClickInitLocation.X;
((Card)sender).Top = e.Y + ((Card)sender).Top - cardClickInitLocation.Y;
}
}
I used my mouseup event before but it's not needed with this method. I cannot see what I could've done wrong.
Fixed it!
Added this to the class:
private Size mouseOffset;
private bool clicked = false;
The three events:
public void CardMouseDown(object sender, MouseEventArgs e)
{
mouseOffset = new System.Drawing.Size(e.Location);
clicked = true;
}
public void CardMouseUp(object sender, MouseEventArgs e)
{
clicked = false;
}
public void CardMouseMove(object sender, MouseEventArgs e)
{
if (clicked)
{
System.Drawing.Point newLocationOffset = e.Location - mouseOffset;
((Card)sender).Left += newLocationOffset.X;
((Card)sender).Top += newLocationOffset.Y;
((Card)sender).BringToFront();
}
}
I have a custom PictureBox which can zoom in using MouseWheel event. Now I want to add a panning feature to it. I mean when PictureBox is in zoomed state, if user left clicks and holds the click then move the mouse, the image would pan within the picturebox.
Here is my code but unfortunately it does not work! I don't know where to look anymore...
private Point _panStartingPoint = Point.Empty;
private bool _panIsActive;
private void CurveBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
Focus();
_panIsActive = true;
_panStartingPoint = e.Location;
}
}
private void CurveBox_MouseUp(object sender, MouseEventArgs e)
{
_panIsActive = false;
}
private void CurveBox_MouseLeave(object sender, EventArgs e)
{
_panIsActive = false;
}
private void CurveBox_MouseMove(object sender, MouseEventArgs e)
{
if(_panIsActive && IsZoomed)
{
var g = CreateGraphics(); //Create graphics from PictureBox
var nx = _panStartingPoint.X + e.X;
var ny = _panStartingPoint.Y + e.Y;
var sourceRectangle = new Rectangle(nx, ny, Image.Width, Image.Height);
g.DrawImage(Image, nx, ny, sourceRectangle, GraphicsUnit.Pixel);
}
}
I am suspecting the MouseMove event...I am not sure if anything happens in this event and/or nx and ny does contain correct point.
Any helps/tips is really appriciated!
I think the math is backwards. Try it like this:
private Point startingPoint = Point.Empty;
private Point movingPoint = Point.Empty;
private bool panning = false;
void pictureBox1_MouseDown(object sender, MouseEventArgs e) {
panning = true;
startingPoint = new Point(e.Location.X - movingPoint.X,
e.Location.Y - movingPoint.Y);
}
void pictureBox1_MouseUp(object sender, MouseEventArgs e) {
panning = false;
}
void pictureBox1_MouseMove(object sender, MouseEventArgs e) {
if (panning) {
movingPoint = new Point(e.Location.X - startingPoint.X,
e.Location.Y - startingPoint.Y);
pictureBox1.Invalidate();
}
}
void pictureBox1_Paint(object sender, PaintEventArgs e) {
e.Graphics.Clear(Color.White);
e.Graphics.DrawImage(Image, movingPoint);
}
You aren't disposing your graphic object, and CreateGraphics is just a temporary drawing anyway (minimizing would erase it) so I moved the drawing code to the Paint event and am just invalidating as the user is panning.
I need inherit events and properties. For example, I need to move a picture around a form.
I have this code to move one picture but I need to create multiple images with the same behavior.
private void pictureBox_MouseDown(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
x = e.X;
y = e.Y;
}
}
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
pictureBox.Left += (e.X -x);
pictureBox.Top += (e.Y - y);
}
}
Create custom control:
public class MovablePictureBox : PictureBox
{
private int x;
private int y;
protected override void OnMouseDown(MouseEventArgs e)
{
base.OnMouseDown(e);
if (e.Button == MouseButtons.Left)
{
x = e.X;
y = e.Y;
}
}
protected override void OnMouseMove(MouseEventArgs e)
{
base.OnMouseMove(e);
if (e.Button == MouseButtons.Left)
{
Left += (e.X - x);
Top += (e.Y - y);
}
}
}
UPDATE:
Instead of attaching a delegates, you should override inherited event functionality, as Microsoft recommends here.
After creating this control just compile program and drag your MovablePictureBoxes from Toolbox to form. They all will be draggable (or movable, if you wish).
What you really want to do is have your multiple PictureBoxes share the same event handlers:
private void pictureBox_MouseMove(object sender, MouseEventArgs e)
{
if (e.Button == MouseButtons.Left)
{
// the "sender" of this event will be the picture box who fired this event
PictureBox thisBox = sender as PictureBox;
thisBox.Left += (e.X -x);
thisBox.Top += (e.Y - y);
}
}
Each PictureBox you create on your form keep hooking them up to the same, already created, event. If you look at the above code you'll notice that it determines which PictureBox called it and affects just that picture box.