VB.Net 如何通过鼠标单击和拖动来旋转矩形

Posted

技术标签:

【中文标题】VB.Net 如何通过鼠标单击和拖动来旋转矩形【英文标题】:VB.Net How to rotate a rectangle by mouse click and drag 【发布时间】:2017-05-03 14:01:33 【问题描述】:

我正在使用带有 PictureBox 和在其上绘制的自定义矩形(人脸检测)的 WinForms。现在我有了在指定坐标上绘制矩形并允许调整矩形大小和移动矩形的代码。但是,我需要知道如何使用鼠标旋转矩形。我知道如何转换它,但不知道如何使用鼠标进行转换。有人可以帮忙吗?

这是自定义矩形的代码:

Imports System
Imports System.Drawing
Imports System.Windows.Forms

Public Class UserRect
    Private Enum PosSizableRect
        UpMiddle
        LeftMiddle
        LeftBottom
        LeftUp
        RightUp
        RightMiddle
        RightBottom
        BottomMiddle
        None
    End Enum

    Private mPictureBox As PictureBox

    Public rect As Rectangle

    Public allowDeformingDuringMovement As Boolean

    Private mIsClick As Boolean

    Private mMove As Boolean

    Private oldX As Integer

    Private oldY As Integer

    Private sizeNodeRect As Integer = 5

    Private mBmp As Bitmap

    Private nodeSelected As UserRect.PosSizableRect = UserRect.PosSizableRect.None

    Private angle As Integer = 30

    Public Sub New(r As Rectangle)
        Me.rect = r
        Me.mIsClick = False
    End Sub

    Public Sub Draw(g As Graphics)
        g.DrawRectangle(New Pen(Color.Red), Me.rect)
        For Each p As UserRect.PosSizableRect In [Enum].GetValues(GetType(UserRect.PosSizableRect))
            g.DrawRectangle(New Pen(Color.Red), Me.GetRect(p))
        Next
    End Sub

    Public Sub SetBitmapFile(filename As String)
        Me.mBmp = New Bitmap(filename)
    End Sub

    Public Sub SetBitmap(bmp As Bitmap)
        Me.mBmp = bmp
    End Sub

    Public Sub SetPictureBox(p As PictureBox)
        Me.mPictureBox = p
        AddHandler Me.mPictureBox.MouseDown, AddressOf Me.mPictureBox_MouseDown
        AddHandler Me.mPictureBox.MouseUp, AddressOf Me.mPictureBox_MouseUp
        AddHandler Me.mPictureBox.MouseMove, AddressOf Me.mPictureBox_MouseMove
        AddHandler Me.mPictureBox.Paint, AddressOf Me.mPictureBox_Paint
    End Sub

    Private Sub mPictureBox_Paint(sender As Object, e As PaintEventArgs)
        Try
            Me.Draw(e.Graphics)
        Catch ex As Exception
            Console.WriteLine(ex.Message)
        End Try
    End Sub

    Private Sub mPictureBox_MouseDown(sender As Object, e As MouseEventArgs)
        Me.mIsClick = True
        Me.nodeSelected = UserRect.PosSizableRect.None
        Me.nodeSelected = Me.GetNodeSelectable(e.Location)
        If Me.rect.Contains(New Point(e.X, e.Y)) Then
            Me.mMove = True
        End If
        Me.oldX = e.X
        Me.oldY = e.Y
    End Sub

    Private Sub mPictureBox_MouseUp(sender As Object, e As MouseEventArgs)
        Me.mIsClick = False
        Me.mMove = False
    End Sub

    Private Sub mPictureBox_MouseMove(sender As Object, e As MouseEventArgs)
        Me.ChangeCursor(e.Location)
        If Not Me.mIsClick Then
            Return
        End If
        Dim rectangle As Rectangle = Me.rect
        Select Case Me.nodeSelected
            Case UserRect.PosSizableRect.UpMiddle
                Me.rect.Y = Me.rect.Y + (e.Y - Me.oldY)
                Me.rect.Height = Me.rect.Height - (e.Y - Me.oldY)
            Case UserRect.PosSizableRect.LeftMiddle
                Me.rect.X = Me.rect.X + (e.X - Me.oldX)
                Me.rect.Width = Me.rect.Width - (e.X - Me.oldX)
            Case UserRect.PosSizableRect.LeftBottom
                Me.rect.Width = Me.rect.Width - (e.X - Me.oldX)
                Me.rect.X = Me.rect.X + (e.X - Me.oldX)
                Me.rect.Height = Me.rect.Height + (e.Y - Me.oldY)
            Case UserRect.PosSizableRect.LeftUp
                Me.rect.X = Me.rect.X + (e.X - Me.oldX)
                Me.rect.Width = Me.rect.Width - (e.X - Me.oldX)
                Me.rect.Y = Me.rect.Y + (e.Y - Me.oldY)
                Me.rect.Height = Me.rect.Height - (e.Y - Me.oldY)
            Case UserRect.PosSizableRect.RightUp
                Me.rect.Width = Me.rect.Width + (e.X - Me.oldX)
                Me.rect.Y = Me.rect.Y + (e.Y - Me.oldY)
                Me.rect.Height = Me.rect.Height - (e.Y - Me.oldY)
            Case UserRect.PosSizableRect.RightMiddle
                Me.rect.Width = Me.rect.Width + (e.X - Me.oldX)
            Case UserRect.PosSizableRect.RightBottom
                Me.rect.Width = Me.rect.Width + (e.X - Me.oldX)
                Me.rect.Height = Me.rect.Height + (e.Y - Me.oldY)
            Case UserRect.PosSizableRect.BottomMiddle
                Me.rect.Height = Me.rect.Height + (e.Y - Me.oldY)
            Case Else
                If Me.mMove Then
                    Me.rect.X = Me.rect.X + e.X - Me.oldX
                    Me.rect.Y = Me.rect.Y + e.Y - Me.oldY
                End If
        End Select
        Me.oldX = e.X
        Me.oldY = e.Y
        If Me.rect.Width < 5 OrElse Me.rect.Height < 5 Then
            Me.rect = rectangle
        End If
        Me.TestIfRectInsideArea()
        Me.mPictureBox.Invalidate()
    End Sub

    Private Sub TestIfRectInsideArea()
        If Me.rect.X < 0 Then
            Me.rect.X = 0
        End If
        If Me.rect.Y < 0 Then
            Me.rect.Y = 0
        End If
        If Me.rect.Width <= 0 Then
            Me.rect.Width = 1
        End If
        If Me.rect.Height <= 0 Then
            Me.rect.Height = 1
        End If
        If Me.rect.X + Me.rect.Width > Me.mPictureBox.Width Then
            Me.rect.Width = Me.mPictureBox.Width - Me.rect.X - 1
            If Not Me.allowDeformingDuringMovement Then
                Me.mIsClick = False
            End If
        End If
        If Me.rect.Y + Me.rect.Height > Me.mPictureBox.Height Then
            Me.rect.Height = Me.mPictureBox.Height - Me.rect.Y - 1
            If Not Me.allowDeformingDuringMovement Then
                Me.mIsClick = False
            End If
        End If
    End Sub

    Private Function CreateRectSizableNode(x As Integer, y As Integer) As Rectangle
        Return New Rectangle(x - Me.sizeNodeRect / 2, y - Me.sizeNodeRect / 2, Me.sizeNodeRect, Me.sizeNodeRect)
    End Function

    Private Function GetRect(p As UserRect.PosSizableRect) As Rectangle
        Select Case p
            Case UserRect.PosSizableRect.UpMiddle
                Return Me.CreateRectSizableNode(Me.rect.X + Me.rect.Width / 2, Me.rect.Y)
            Case UserRect.PosSizableRect.LeftMiddle
                Return Me.CreateRectSizableNode(Me.rect.X, Me.rect.Y + Me.rect.Height / 2)
            Case UserRect.PosSizableRect.LeftBottom
                Return Me.CreateRectSizableNode(Me.rect.X, Me.rect.Y + Me.rect.Height)
            Case UserRect.PosSizableRect.LeftUp
                Return Me.CreateRectSizableNode(Me.rect.X, Me.rect.Y)
            Case UserRect.PosSizableRect.RightUp
                Return Me.CreateRectSizableNode(Me.rect.X + Me.rect.Width, Me.rect.Y)
            Case UserRect.PosSizableRect.RightMiddle
                Return Me.CreateRectSizableNode(Me.rect.X + Me.rect.Width, Me.rect.Y + Me.rect.Height / 2)
            Case UserRect.PosSizableRect.RightBottom
                Return Me.CreateRectSizableNode(Me.rect.X + Me.rect.Width, Me.rect.Y + Me.rect.Height)
            Case UserRect.PosSizableRect.BottomMiddle
                Return Me.CreateRectSizableNode(Me.rect.X + Me.rect.Width / 2, Me.rect.Y + Me.rect.Height)
            Case Else
                Return Nothing
        End Select
    End Function

    Private Function GetNodeSelectable(p As Point) As UserRect.PosSizableRect
        For Each posSizableRect As UserRect.PosSizableRect In [Enum].GetValues(GetType(UserRect.PosSizableRect))
            If Me.GetRect(posSizableRect).Contains(p) Then
                Return posSizableRect
            End If
        Next
        Return UserRect.PosSizableRect.None
    End Function

    Private Sub ChangeCursor(p As Point)
        Me.mPictureBox.Cursor = Me.GetCursor(Me.GetNodeSelectable(p))
    End Sub

    Private Function GetCursor(p As UserRect.PosSizableRect) As Cursor
        Select Case p
            Case UserRect.PosSizableRect.UpMiddle
                Return Cursors.SizeNS
            Case UserRect.PosSizableRect.LeftMiddle
                Return Cursors.SizeWE
            Case UserRect.PosSizableRect.LeftBottom
                Return Cursors.SizeNESW
            Case UserRect.PosSizableRect.LeftUp
                Return Cursors.SizeNWSE
            Case UserRect.PosSizableRect.RightUp
                Return Cursors.SizeNESW
            Case UserRect.PosSizableRect.RightMiddle
                Return Cursors.SizeWE
            Case UserRect.PosSizableRect.RightBottom
                Return Cursors.SizeNWSE
            Case UserRect.PosSizableRect.BottomMiddle
                Return Cursors.SizeNS
            Case Else
                Return Cursors.[Default]
        End Select
    End Function
End Class

【问题讨论】:

请注意,旋转后,所有其他简单的变换都应该以不同的方式完成。例如。水平轴将不再与正常的 x 方向对齐。因此,您当前的代码需要非常修改,因为它没有考虑到这一点! 这取决于你想如何增加 - 减少旋转角度。水平、垂直等移动鼠标 【参考方案1】:

这是场景: 当用户第一次按下鼠标时,检查是否也按下了CTRL键ModifierKeys = Keys.Control然后我们应该开始旋转(CTRL键是为了区分移动和旋转)。为此,我们应该知道旋转中心以及旋转量(旋转角度)。我们可以假设矩形(面)的中心是我们的旋转中心。要找到旋转角度,我们应该做一些计算:

Dim a1, a2, delta as Double
a1 = Math.Atan2(yA-yO, xA-xO)
a2 = Math.Atan2(yB-yO, xB-xO)
delta = a2 - a1 'this is the angle AOB (in radians) to be applied for rotation to all 4 points 

【讨论】:

谢谢.. 但我的数学很烂。你的代码中有这个吗? 我认为最好计算角度 AOB 而不是实际点 A2。这样旋转会更容易,而不是计算其余三个点的坐标。

以上是关于VB.Net 如何通过鼠标单击和拖动来旋转矩形的主要内容,如果未能解决你的问题,请参考以下文章

如何通过鼠标拖动选择铁选择器中的多个元素

OpenGL用鼠标拖动绘制矩形?

在opengl中,如何将鼠标跟随更改为鼠标单击、拖动和释放?

如何识别 QGraphicsView 鼠标移动事件?

在 MFC 中通过鼠标单击而不是按下拖动动作进行选择

HTML5 Canvas 中旋转矩形内的鼠标位置