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

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

Я уже сделал часть перетаскивания и столкновения, но я борюсь с привязкой к кнопке. Картинная коробка имеет размер двух кнопок. Я попытался выровнять picture box с помощью кнопок, используя picture box.lef t = 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

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) получит только элементы управления определенного типа (в этом случае Button с). Итерация только через 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 вместо And, а также OrElse вместо Or в If Заявления с AndAlso а также OrElse закорочены.

Другие вопросы по тегам