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 如何通过鼠标单击和拖动来旋转矩形的主要内容,如果未能解决你的问题,请参考以下文章