Привязать PictureBox к кнопкам после перетаскивания

Я делаю игру «Морской бой» и использую кнопки в качестве сетки (игрового поля). Я использую коробку с картинками в качестве корабля и пытаюсь сделать так, чтобы коробка с картинками привязывалась к кнопкам, с которыми она сталкивается.

Я уже сделал перетаскивание и столкновение, но я борюсь с привязкой к кнопкам. Поле с изображением размером с две кнопки. Я попытался выровнять изображение с кнопками, используя picturebox.left = button.left, но он выбрал неправильную кнопку из двух.

Dim Off As Point
Private Sub picDestroyer_MouseDown(sender As Object, e As MouseEventArgs) Handles picDestroyer.MouseDown
    Off.X = MousePosition.X - sender.Left 'Click and Drag ship
    Off.Y = MousePosition.Y - sender.Top
End Sub

Private Sub picDestroyer_MouseMove(sender As Object, e As MouseEventArgs) Handles picDestroyer.MouseMove
    If e.Button = MouseButtons.Left Then
        sender.Left = MousePosition.X - Off.X 'Click and Drag ship
        sender.Top = MousePosition.Y - Off.Y
    End If
End Sub
Private Sub picDestroyer_DoubleClick(sender As Object, e As EventArgs) Handles picDestroyer.DoubleClick
    If picDestroyer.Size = New Size(52, 21) Then 'Rotate Pic if double clicked
        picDestroyer.Size = New Size(21, 52)
    ElseIf picDestroyer.Size = New Size(21, 52) Then
        picDestroyer.Size = New Size(52, 21)
    End If
End Sub
Private Sub picDestroyer_MouseLeave(sender As Object, e As EventArgs) Handles picDestroyer.MouseLeave

    For Each button In Me.Controls
        If picDestroyer.Bounds.IntersectsWith(button.bounds) Then
            button.backcolor = Color.Red
            picDestroyer.BackColor = SystemColors.Control
        End If
        If picDestroyer.Bounds.IntersectsWith(button.bounds) And picDestroyer.Size = New Size(52, 21) Then
            picDestroyer.Top = button.top
        End If
        If picDestroyer.Bounds.IntersectsWith(button.bounds) And picDestroyer.Size = New Size(21, 52) Then
            picDestroyer.Left = button.left
        End If
    Next

person Erika    schedule 23.01.2017    source источник


Ответы (1)


Чтобы получить кнопку, к которой вы хотите привязаться, вы можете временно отключить PictureBox и вызвать GetChildAtPoint() в форме, чтобы получить дочерний элемент управления в расположении PictureBox, указав GetChildAtPointSkip.Disabled в качестве второго параметра, чтобы поиск не будет включать ваш отключенный PictureBox, но все остальные элементы управления выше/ниже него.

После этого вы можете просто установить координаты PictureBox на координаты кнопки.

Есть также несколько улучшений, которые можно внести в ваш код:

  • Вы можете использовать событиеMouseUp вместо MouseLeave, чтобы обновить позицию окна с изображением сразу после того, как вы его перетащите.

  • Установите обе координаты X и Y для окна изображения при привязке (а не только одну из них, Left = X, Top = Y), чтобы оно правильно привязывалось в верхнем левом углу кнопки.

  • В цикле перебираем Me.Controls.OfType(Of Button)() вместо Me.Controls, поскольку OfType(Of TResult) получит только элементы управления определенного типа (в данном случае Buttons). Перебор только Me.Controls, например, будет включать сам PictureBox, что может вызвать проблемы в будущем (возможно, именно поэтому вы каждый раз устанавливали для BackColor значение Control?).

Все, что сказал, этот код должен работать:

If e.Button = Windows.Forms.MouseButtons.Left Then

    picDestroyer.Enabled = False 'Temporarily disable the picture box so that it isn't included in the child search.
    Dim ChildBelowDestroyer As Control = Me.GetChildAtPoint(picDestroyer.Location, GetChildAtPointSkip.Disabled) 'Look for any child control that isn't disabled.
    picDestroyer.Enabled = True 'Re-enable the picture box.

    If ChildBelowDestroyer Is Nothing OrElse _
        ChildBelowDestroyer.GetType() IsNot GetType(Button) Then
        Return 'Do not continue if no child was found below the picture box, or if the child is not a button.
    End If

    picDestroyer.Location = ChildBelowDestroyer.Location 'Snap the picture box to the button (sets the X- and Y-coordinates).

    For Each button In Me.Controls.OfType(Of Button)() 'OfType() to only look for buttons.
        If picDestroyer.Bounds.IntersectsWith(button.Bounds) Then
            button.BackColor = Color.Red
            picDestroyer.BackColor = SystemColors.Control
        End If
    Next

End If

Следует также помнить об использовании AndAlso< /a> вместо And и OrElse вместо Or в операторах If, поскольку AndAlso и OrElse являются замыканием.

person Visual Vincent    schedule 23.01.2017
comment
После добавления Exit For в оператор if цвет фона кнопки больше не меняется на красный. Также больше не работает picDestroyer.top = button.top и picDestroyer.Left = button.left. Я также объединил операторы if, и мой код выглядит идентично тому, что вы предоставили. Я ценю помощь - person Erika; 24.01.2017
comment
@Erika: Хм, это странно ... Тогда мне придется попробовать код. - person Visual Vincent; 24.01.2017
comment
@Erika Эрика: я обновил весь ответ новым кодом и некоторыми пояснениями. Надеюсь, это будет то, что вам нужно! - person Visual Vincent; 24.01.2017
comment
Большое спасибо за помощь! Когда я пробовал If e.Button = Windows.Forms.MouseButtons.Left Then, e.button было подчеркнуто, говоря, что e.button не является членом system.eventargs. Я полностью избавился от оператора if, и он все еще работал. Спасибо за помощь, я очень ценю это! - person Erika; 25.01.2017
comment
@Erika: Рад, что смог помочь! -- Для работы e.Button у вас должно быть правильное объявление события. Лучший способ получить его — удалить все существующие обработчики, а затем выбрать событие из окна событий в Visual Studio. Правильным объявлением для MouseUp было бы: Private Sub picDestroyer_MouseUp(sender As Object, e As MouseEventArgs) Handles picDestroyer.MouseUp — обратите внимание на e As MouseEventArgs. - person Visual Vincent; 25.01.2017