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

时间:2014-08-31 03:28:42

标签: c# winforms

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

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

然而,这段代码允许向任何方向移动,我想限制其移动到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 PassantTaW的答案,我从中提取了构建一个小型2D引擎的想法,能够界定可以移动多个控件的区域。在面板容器内,考虑到碰撞检测,防止和控制运动方向的限制,由所需的许多自定义因素强加。我想接受这两个答案,但由于这是不可能的,我接受了对这个问题提供最深入了解的答案。

2 个答案:

答案 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);
    }