我在这里围绕一些试图解决问题的代码来燃烧午夜的油。
下面的代码将设置控件,以便能够在其父控件内的任何位置移动。
然而,这段代码允许向任何方向移动,我想限制其移动到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 (left<->right 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引擎的想法,能够界定可以移动多个控件的区域。在面板容器内,考虑到碰撞检测,防止和控制运动方向的限制,由所需的许多自定义因素强加。我想接受这两个答案,但由于这是不可能的,我接受了对这个问题提供最深入了解的答案。
答案 0 :(得分:3)
这是一个例子。我添加了一个脚本化的小Panel
&#39;&#39;到更大的Panel
&#39;董事会&#39;。
我检查了一个最小的三角形,这样一只颤抖的手不会开始运动..
一个标志跟踪运动,另一个标志跟踪方向,用&#39; 0&#39;还没有&#39;决定。
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
点击状态,因此我将发件人和发件人2命名为&#39;我使用它来允许相同的代码用于许多部分。
答案 1 :(得分:3)
你无法按照预期使其可靠。该UI问题的常见解决方案是向用户提供可以根据需要打开和关闭的辅助。 Shift键是常用的选择。在关闭时允许自由移动,但在按住时按主导方向拍摄。
使用Control.ModifierKeys属性检查MouseMove事件处理程序中的键是否已关闭。您需要KeyDown和KeyUp事件处理程序,以便您可以看到按下并释放Shift键。正确跟随鼠标位置需要进行重大更改,按住Shift键时不一定会在控件上方悬停。足够的移动部件将其封装在辅助类中:
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);
}