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

橡皮筋线条

starIconstarIconstarIconstarIcon
emptyStarIcon
starIcon

4.74/5 (15投票s)

2005年11月2日

3分钟阅读

viewsIcon

98236

downloadIcon

1293

将橡皮筋线用作标尺。

Sample Image - Rubberbands.jpg

引言

本文介绍了创建用于创建“橡皮筋”样式标尺的小类的过程,该标尺可用于任何项目。它使用 GDI+ 中的一项技术来替换具有许多问题的 ControlPaint.DrawReversibleLine,我将不在此处详细介绍这些问题。请注意,此代码是使用 VS2005 编写的,但没有理由它不能在早期版本中使用,只需确保更改 Using 命令。

背景

我试图创建一个需要我绘制平面图的应用程序,这导致了一个问题,即如何向用户显示要绘制的墙的长度。我最初从众所周知的、有文档记录的 .NET 方法 DrawReversibleLine 开始,该方法位于 ControlPaint 类中。但这导致了很多问题,其中一些是世界坐标相关性、绘画问题(XOR 绘图在很多方面都有缺陷)、颜色选择(没有颜色选择)等等,但它们是主要的问题。所以我决定编写自己的类。

使用代码

我首先将可逆线代码保留在 MouseDownMouseMoveMouseUp 事件中,这可以在许多关于绘制可逆线的文章中找到,所以我不会详细介绍。简而言之,MouseDown 存储起点,MouseMove 完成设置当前点和使控件表面无效的繁重工作,以便它将重新绘制,然后最后 MouseUp 事件触发事件以通知侦听器已定义两个点。

在此橡皮筋线的实现中有几个超出常规范畴的技巧,我想分享的就是它们。

第一个是在线的中间添加一个文本标签(随着线的移动而旋转),该标签显示线的长度。第二个是该类仅绘制已更改的控件部分的方式。

文本标签(旋转文本)

这是最难实现的工作,但 GDI+ 库中的一些功能使这项任务更容易。首先要克服的是长度本身,但基本的三角学解决了这个问题

' length^2 = width^2 + height^2

length = Math.Sqrt(rect.Width ^ 2 + rect.Height ^ 2)

现在我所要做的就是将该值放到线上,并旋转以跟随该线,为此我需要旋转文本的角度。再次,三角学进行了救援,给了我以下答案

angle = Math.Atan((p1.Y - p2.Y) / (p1.X - p2.X)) * (180 / Math.PI)

现在有了 LineLengthAngle 函数,我将以下部分组合在一起,并将其添加到 Paint 事件(如果鼠标仍然按下)。该矩阵用于围绕线的中心点执行旋转,以便在绘制椭圆和文本时,它们实际上是在旋转的图形设备上绘制的。字符串格式仅用于确保文本位于线的中心,这比尝试在用于绘制椭圆的矩形中绘制文本要好得多。椭圆的目的是确保无论背景如何,都可以始终轻松读取文本。

Using mx As New System.Drawing.Drawing2D.Matrix
    mx.Translate(midPoint.X, midPoint.Y)
    mx.Rotate(Angle(_origin, _last))
    e.Graphics.Transform = mx
    Using sf As New StringFormat()
        Dim ls As String = CInt(LineLength(_origin, _last))
        Dim l As SizeF = e.Graphics.MeasureString(ls, _
                         _parent.Font, _parent.ClientSize, sf)
        sf.LineAlignment = StringAlignment.Center
        sf.Alignment = StringAlignment.Center

        Dim rt As New Rectangle(0, 0, l.Width, l.Height)
        rt.Inflate(3, 3)
        rt.Offset(-(l.Width / 2), -(l.Height / 2))
        Using backBrush As New SolidBrush(_backColor)
            e.Graphics.FillEllipse(backBrush, rt)
        End Using
        Using foreBrush As New SolidBrush(_foreColor)
            e.Graphics.DrawString(ls, _parent.Font, foreBrush, 0, 0, sf)
        End Using
    End Using
End Using

使用该类

实际使用该类就像将其添加到您的项目,然后根据需要实例化该类一样容易。以下代码在表单中使用该类。(在 Dispose 方法中,请务必释放该类。)注意在表单上设置的样式以防止闪烁。

Public Class Form1
    Private WithEvents _ruler As MouseRuler

    Public Sub New()

        ' This call is required by the Windows Form Designer.
        InitializeComponent()

        ' Add any initialization after the InitializeComponent() call.
        Me.SetStyle(ControlStyles.OptimizedDoubleBuffer Or _
                    ControlStyles.AllPaintingInWmPaint, True)

        _ruler = New MouseRuler(Form1)
    End Sub

    Private Sub _ruler_CaptureFinished(ByVal sender As Object, _
                ByVal e As CaptureEventArgs) Handles _ruler.CaptureFinished
        'todo:  Add wall between points in CaptureEventArgs
    End Sub
End Class

历史

迄今为止所做的更改

  • 无。
© . All rights reserved.