我有一个程序,可以用鼠标在四个方向中的任何一个上绘制矩形。
这些矩形用于pictureBox上以裁剪图像的一部分。
必须在保持给定尺寸比例(例如320 x 200)的同时绘制这些矩形。
我希望此工具的行为与Photoshop中的裁切工具非常相似,或者与此处的裁切示例一样: https://imageresize.org/
我的大多数元素都能正常工作,我只是在努力进行一些几何计算。
请参见我的代码中的“右下”示例。效果很好,基本上我只想将此确切公式应用于其他方向。
几个小时来我一直在进行不同的计算,但似乎无法解决。
这是工作代码:
Protected Overrides Sub OnMouseMove(ByVal e As MouseEventArgs)
'Draw rectangle keeping aspect ratio
If e.Button = Windows.Forms.MouseButtons.Left Then
If e.X > startPos.X And e.Y > startPos.Y Then
'Bottom right
mRect = New Rectangle(mRect.Left, mRect.Top, e.X - mRect.Left, e.Y - mRect.Top)
mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
If e.Y < mRect.Bottom Then
mRect = Rectangle.FromLTRB(startPos.X, startPos.Y, e.X, e.Y)
mRect.Size = New Size(mRect.Height * Ratio.Text, mRect.Height)
End If
Me.Invalidate()
ElseIf e.X < startPos.X And e.Y > startPos.Y Then
'Bottom left
mRect = New Rectangle(e.X, startPos.Y, startPos.X - e.X, e.Y - startPos.Y)
mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
Me.Invalidate()
ElseIf e.X > startPos.X And e.Y < startPos.Y Then
'Top right
mRect = New Rectangle(startPos.X, e.Y, e.X - startPos.X, startPos.Y - e.Y)
mRect.Size = New Size(mRect.Height * 1.6, mRect.Height)
Me.Invalidate()
ElseIf e.X < startPos.X And e.Y < startPos.Y Then
'Top left
mRect = New Rectangle(e.X, e.Y, startPos.X - e.X, startPos.Y - e.Y)
mRect.Size = New Size(mRect.Width, mRect.Width / Ratio.Text)
Me.Invalidate()
End If
End If
End Sub
任何帮助将不胜感激。谢谢!
下面是当前的工作方式,您可以在西北地区进行绘制时看到时髦。对于所有象限,我都需要具有与东南相同的行为(或代码的右下角)。
答案 0 :(得分:1)
您有具有给定比率和尺寸sw, sh
的示例矩形S(在您的示例中为320x200)
鼠标位置形成尺寸为nw, nh
(绝对值!)的新矩形N。
据我所知,您的任务是将与S具有相同比率的矩形刻入矩形N,获得基点为(rx0, ry0)
和尺寸为(rw, rh)
的矩形R
nx0 = min(e.x, startpos.x)
ny0 = min(e.y, startpos.y)
nw = abs(e.x - startpos.x)
nh = abs(e.y - startpos.y)
if nw * sh >= nh * sw then // if N is "too wide"
rh = nh
rw = rh * sw / sh
ry0 = ny0
rx0 = nx0 + (nw - rw) / 2
else // N is "too slim"
rw = nw
rh = rw * sh / sw
rx0 = nx0
ry0 = ny0 + (nh - rh) / 2
然后
mRect = New Rectangle(rx0, ry0, rx0 + rw, ry0 + rh)
答案 1 :(得分:1)
当将“比率”应用于“矩形”尺寸时,我提出了一种略有不同的方法来计算光标的当前位置。
您当然需要使用Control的MouseDown事件保存Rectangle的开始位置,然后使用MouseMove事件来跟踪Mouse的运动。
照常计算光标的当前位置(当偏移量为负时,交换当前光标的位置和起始位置)。
唯一的区别是矩形的高度,而整体尺寸受“比率”约束。
在这种情况下, Rectangle.Location.Y
由 Rectangle.Width / Ratio
度量确定。如果 Cursor.Location.Y
位于起始位置(Cursor.Location.Y <= StartingPosition.Y
上方,则此位置可见。就像您发布的代码一样。
在此示例中,我使用了一个自定义的Rectangle类,该类包含绘制形状所需的所有信息,无论是否在其尺寸上应用了特定的Ratio。
请注意,
Ratio
被硬编码为1.6
:仅用于 测试,当然可以将其设置为其他任何内容。
结果的可视示例:
Private DrawingRects As List(Of DrawingRectangle) = New List(Of DrawingRectangle)()
Private Sub PicureBox1_MouseDown(sender As Object, e As MouseEventArgs) Handles PicureBox1.MouseDown
If e.Button = MouseButtons.Left Then
DrawingRects.Add(New DrawingRectangle() With {
.DrawingcColor = Color.LightGreen,
.Location = e.Location,
.Owner = CType(sender, Control),
.Ratio = 1.6,
.Size = Size.Empty,
.StartPosition = e.Location
})
End If
End Sub
Private Sub PicureBox1_MouseMove(sender As Object, e As MouseEventArgs) Handles PicureBox1.MouseMove
If e.Button = MouseButtons.Left Then
Dim rect As DrawingRectangle = DrawingRects.Last()
If e.X < rect.StartPosition.X Then rect.Location = New Point(e.X, rect.Location.Y)
If e.Y < rect.StartPosition.Y Then rect.Location = New Point(rect.Location.X, e.Y)
Dim currentWidth As Integer = Math.Abs(rect.StartPosition.X - e.X)
If rect.Ratio = 1.0F Then
rect.Size = New Size(currentWidth, Math.Abs(rect.StartPosition.Y - e.Y))
Else
If rect.StartPosition.Y <= rect.Location.Y Then
rect.Size = New Size(currentWidth, CType(Math.Abs(rect.StartPosition.X - e.X) / rect.Ratio, Integer))
Else
Dim currentHeight As Integer = CType(currentWidth / rect.Ratio, Integer)
rect.Location = New Point(rect.Location.X, rect.StartPosition.Y - currentHeight)
rect.Size = New Size(currentWidth, currentHeight)
End If
End If
DrawingRects(DrawingRects.Count - 1) = rect
DirectCast(sender, Control).Invalidate()
End If
End Sub
Private Sub PicureBox1_Paint(sender As Object, e As PaintEventArgs) Handles PicureBox1.Paint
Dim canvas As Control = DirectCast(sender, Control)
If DrawingRects.Count > 0 Then
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias
For Each rect As DrawingRectangle In DrawingRects
If canvas IsNot rect.Owner Then Continue For
Using pen As New Pen(rect.DrawingcColor, rect.PenSize)
e.Graphics.DrawRectangle(pen, New Rectangle(rect.Location, rect.Size))
End Using
Next
End If
End Sub
DrawingRectangle
类:
注意:该类具有
Owner
属性,引用了当前的Control 绘制形状的位置:允许将List(Of DrawingRectangle)
与 同时使用不同的控件。
Public Class DrawingRectangle
Private rectAspect As SizeF = SizeF.Empty
Private rectRatio As Single = 0F
Public Property Owner As Control
Public Property Location As Point
Public Property Size As Size
Public Property StartPosition As Point
Public Property DrawingcColor As Color
Public Property PenSize As Single
Public Property Aspect() As SizeF
Get
Return rectAspect
End Get
Set(ByVal value As SizeF)
Me.rectAspect = value
SetAspectRatio(value)
End Set
End Property
Public Property Ratio As Single
Get
Return rectRatio
End Get
Set(ByVal value As Single)
rectRatio = value
SetAspectRatio(value)
End Set
End Property
Private Sub SetAspectRatio(aspect As SizeF)
Me.rectRatio = aspect.Width / aspect.Height
End Sub
Private Sub SetAspectRatio(ratio As Single)
Me.rectAspect = New SizeF(100, 100 / ratio)
End Sub
End Class