水平或垂直移动控制,而不是两者的组合

我在这里围绕一些试图解决问题的代码来燃烧午夜的油。

下面的代码将设置控件,以便能够在其父控件内的任何位置移动。

然而,这个代码允许在任何方向上移动,我想将其移动限制在X轴或Y轴上,这意味着用户可以水平或垂直移动它,而不是两者的组合。

Point lastPosition = Point.Empty; control.MouseDown += (sender, evt) => { lastPosition = evt.Location; }; control.MouseMove += (sender, evt) => { // This moves the control anywhere. // I only want to move in one direction (leftright or top  down) never diagonally // Not sure how to first find which direction the user wants to move, // nor how to restrict the movement to only one of the directions mentioned int x = last.X + movingPiece.Left - mouseDownLocation.X; int y = last.Y + movingPiece.Top - mouseDownLocation.Y; movingPiece.Left = x; movingPiece.Top = y; }; 

谢谢

感谢Hans Passant和TaW的回答,我从中提取了我构建一个小型2D引擎的想法,能够划分区域容器内可以移动多个控件的区域,同时考虑到碰撞检测,预防和控制运动方向的限制由一些自定义因素强加所要求。 我想接受这两个答案,但由于这是不可能的,我接受了答案,他对这个问题提供了最深刻的见解。

这是一个例子。 我将一个脚本化的小Panel ‘片’添加到一个更大的Panel ‘板’。

我检查了最小的三角形,这样一只颤抖的手不会开始运动。

一个标志跟踪运动,另一个标志跟踪方向,“0”表示“尚未”决定。

 bool pieceMoving = false; byte pieceDirection = 0; Point startPosition = Point.Empty; private void AddPieceButton_Click(object sender, EventArgs e) { Panel newPiece = new Panel(); newPiece.Size = new Size(16, 16); newPiece.BackColor = Color.Blue; pan_board.Controls.Add(newPiece); newPiece.MouseDown += (sender2, evt) => { pieceMoving = true; pieceDirection = 0; startPosition = evt.Location; }; newPiece.MouseUp += (sender2, evt) => { pieceMoving = false; pieceDirection = 0;}; newPiece.MouseMove += (sender2, evt) => { int delta = 0; if (!pieceMoving) return; if (pieceDirection == 0) { int deltaX = Math.Abs(startPosition.X - evt.X); int deltaY = Math.Abs(startPosition.Y - evt.Y); delta = deltaX + deltaY; if (deltaX == deltaY) return; if (delta < 6) return; // some minimum movement value if (deltaX > deltaY) pieceDirection = 1; else pieceDirection = 2; } // else if (delta == 0) { pieceDirection = 0; return; } // if you like! Panel piece = (Panel) sender2; if (pieceDirection == 1) piece.Left += evt.X; else piece.Top += evt.Y; }; 

由于我已经将代码放在Button单击中,因此我将发送者命名为’sender2’,并且我使用它来允许将相同的代码用于许多部分。

你无法按照预期使其可靠。 此UI问题的常见解决方案是为用户提供可以根据需要打开和关闭的帮助。 Shift键是常用的选择。 关闭时允许自由移动,但在按住时沿主导方向拍打。

您使用Control.ModifierKeys属性来检查您的MouseMove事件处理程序中的键是否已关闭。 您需要KeyDown和KeyUp事件处理程序,以便您可以看到按下并释放Shift键。 正确跟随鼠标位置需要进行重大更改,按住Shift键时不一定要在控件上方hover。 足够的移动部件将其封装在辅助类中:

 class ControlMover { private Control control; private Point downPos; private Point startPos; enum Constrains { None, Hor, Ver }; private Constrains constraint; public ControlMover(Control ctl) { control = ctl; startPos = control.Location; downPos = Cursor.Position; control.Capture = true; control.MouseMove += control_MouseMove; control.MouseUp += control_MouseUp; control.MouseCaptureChanged += control_MouseCaptureChanged; control.KeyDown += control_KeyDown; control.KeyUp += control_KeyUp; } void handleKey(Keys key, bool down) { Console.WriteLine((int)key); if (key == Keys.Escape) { control.Capture = false; control.Location = startPos; } else if ((key & Keys.KeyCode) == Keys.ShiftKey) { if (!down) constraint = Constrains.None; else if (constraint == Constrains.None) { var curPos = Cursor.Position; if (Math.Abs(curPos.X - downPos.X) >= Math.Abs(curPos.Y - downPos.Y)) constraint = Constrains.Hor; else constraint = Constrains.Ver; } moveControl(); } } void control_MouseCaptureChanged(object sender, EventArgs e) { // This ends it if (control.Capture) return; control.MouseMove -= control_MouseMove; control.MouseUp -= control_MouseUp; control.MouseCaptureChanged -= control_MouseCaptureChanged; control.KeyDown -= control_KeyDown; control.KeyUp -= control_KeyUp; } private void moveControl() { var curPos = Cursor.Position; if (constraint == Constrains.Hor) curPos.Y = downPos.Y; if (constraint == Constrains.Ver) curPos.X = downPos.X; curPos = control.Parent.PointToClient(curPos); // Keep it inside the parent curPos.X = Math.Max(0, curPos.X); curPos.Y = Math.Max(0, curPos.Y); curPos.X = Math.Min(control.Parent.ClientSize.Width - control.Width, curPos.X); curPos.Y = Math.Min(control.Parent.ClientSize.Height - control.Height, curPos.Y); control.Location = curPos; } void control_MouseUp(object sender, MouseEventArgs e) { control.Capture = false; } void control_MouseMove(object sender, MouseEventArgs e) { moveControl(); } void control_KeyDown(object sender, KeyEventArgs e) { handleKey(e.KeyData, true); } void control_KeyUp(object sender, KeyEventArgs e) { handleKey(e.KeyData, false); } } 

样品用法:

  private void button1_MouseDown(object sender, MouseEventArgs e) { new ControlMover(button1); }