65.9K
CodeProject 正在变化。 阅读更多。
Home

GDI+ 中调整和旋转形状

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.97/5 (12投票s)

2017 年 12 月 30 日

CPOL

2分钟阅读

viewsIcon

30324

downloadIcon

2935

绘制一个类似形状的编辑器,实现使用锚点来调整和旋转选定矩形的功能

引言

该代码实现了一个鼠标驱动的形状编辑器,支持通过锚点移动、调整大小和旋转选定矩形,这些锚点可用于轮廓显示任何类型的内容,例如图像、形状、文本等。

背景

在 GDI+ 中绘制旋转元素是一项相当简单的任务。通过鼠标移动创建调整大小机制也很简单。当您尝试调整旋转元素的大小时,可能会出现一些问题,这是由于 GDI+ 允许您围绕给定点(通常是中心)旋转形状的方式造成的。

经过许多天令人沮丧的 Google 搜索,我提出了这个解决方案,并在此分享,希望能帮助您节省时间。

Using the Code

窗体的 mouse_ 事件显示了如何处理鼠标移动以及如何检测正在执行的操作类型(moveresizerotate)。

所有绘图都发生在 Render 方法中,该方法还负责存储用于鼠标事件的区域,以检测鼠标的位置和使用方式。

在处理旋转对象时,需要通过区域(或路径)进行鼠标命中测试,以便正确地将光标位置与屏幕上的元素关联起来。

在调整旋转元素的大小时,**关键是选择正确的中心原点进行旋转**,即在调整大小开始之前最后一次渲染矩形时的中心。

' Define center origin
Dim ptCenter As PointF = _
      New PointF(_rcRect.Left + (_rcRect.Width / 2), _rcRect.Top + (_rcRect.Height / 2))

' Check for on-going resize operation
Select Case _eMouseOperation
    Case MouseOperation.Nwse To MouseOperation.We
        ' Use last known center origin
        ptCenter = _ptCenter
    Case Else
        _ptCenter = ptCenter
End Select

此外,在渲染旋转元素后,需要计算矩形在平坦状态下的位置,围绕新的中心原点进行计算。这将是调整大小操作完成后要使用的新的矩形。

' Check for rotation
If (_rgRect IsNot Nothing) AndAlso (_snAngle <> 0.0) Then

    ' Get rotatetd rectangle bounds
    Dim rfNewBounds As RectangleF = _rgRect.GetBounds(oGfx)

    ' Check for resize operation on a rotated element
    If (_eMouseOperation >= MouseOperation.Nwse) AndAlso _eMouseOperation <= MouseOperation.We Then

        ' Get center origin of the region
        Dim ptNewScreenCenterOrigin As New PointF_
          (rfNewBounds.Left + (rfNewBounds.Width / 2), rfNewBounds.Top + (rfNewBounds.Height / 2))

        ' Compute a rectangle based on source rectangle size and located around the center point
        ' of the bounds of the rotated region
        Dim rcNewRenderRect As New RectangleF((ptNewScreenCenterOrigin.X - (_rcRect.Width / 2)), _
                                              (ptNewScreenCenterOrigin.Y - (_rcRect.Height / 2)), _
                                              _rcRect.Width, _
                                              _rcRect.Height)

        ' Store for mouse up
        _rcResizeMouseUpRenderRect = rcNewRenderRect

    End If

End If

关注点

AnchorToCursor 方法返回当鼠标悬停在其中一个锚点上时最合适的光标。选择会考虑到锚点类型(基本点)和当前的旋转角度。事实证明,渲染自定义旋转箭头光标可能会导致不良结果,因此最好始终使用一个工厂箭头,即使角度与旋转/基本点不完全匹配。
Microsoft Office 形状编辑器使用相同的方法。

历史

  • 首次提交于 2017 年 12 月 30 日
  • 已修复错误并提交于 2021 年 12 月 9 日
© . All rights reserved.