2014-08-31 3 views
0

Я был здесь, сжигая полночное масло вокруг некоторых строк кода, пытаясь решить проблему.Переместить управление горизонтально или вертикально, а не комбинацию обоих

Код ниже будет регулировать элемент управления, чтобы он мог перемещаться в любом месте своего родительского элемента управления.

Однако этот код позволяет двигаться в любом направлении, я хотел бы ограничить его перемещение либо по оси 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

Что ваш вопрос? – xxbbcc

+0

@xxbbcc Для уточнения я отредактировал и предоставил образец кода и мою цель в нем. Спасибо, если вы можете помочь. –

+0

Ну, первый шаг к решению будет для __you__, чтобы принять решение о __which__ движение должно случиться! – TaW

ответ

3

Вот пример. Я добавляю небольшую сцену размером 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» отправителя и я использую его, чтобы обеспечить тот же код используется для многих частей.

+0

Я сделал схожую с этим в wpf - единственное изменение, которое я сделал бы, это проверить, чтобы движение достигло минимальной суммы до совершения. Я обнаружил, что небольшое перемещение по вертикали довольно распространено при движении по горизонтали, поэтому установите границу около 10 пикселей. Когда движение выходит за пределы этого диапазона, оно блокируется, а другая ось возвращается к нулю. – kidshaw

+0

Совершенно верно, поэтому я добавил строку выше. Моя рука настолько спокойная, что я убираюсь с 6 пикселями ;-) – TaW

+0

Стоит +1 сейчас;) – kidshaw

3

Вы не можете быть надежным. Общим решением для этой проблемы пользовательского интерфейса является предоставление пользователю помощи, которую он может включать и отключать по желанию. Для этого используется клавиша 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); 
    } 
+0

К сожалению, для этого приложения клавиатурный ввод невозможен. Однако код обеспечивал понимание областей кодирования разрабатываемого приложения. Спасибо. –

Смежные вопросы