GDI+绘制自定义行距的文本(续)

  在上文“GDI+绘制自定义行距的文本的三种方法。”中,介绍了绘制自定义行间距的多行文本的方法。

  在第三种的方法中,启用了GdipDrawDriverString这个函数。这个函数可以定义每个字符的位置,这是它的优点。不过它的缺点也比较明显。一是它定义的字符位置是以字符的左下角为基准的,和一般的概念是两样的。二是他对Font要求比较高,据说如果采用的是英文字体,在显示中文时会显示成一个个小方块。

  再翻翻GDIP中的其他函数,发现graphics的DrawString的方法都是调用GdipDrawString这个函数。如果我们能跳过graphics直接调用GdipDrawString这个函数,是不是能提高效率呢?我们试试看。

  <DllImport("gdiplus.dll", CharSet:=CharSet.Unicode, SetLastError:=True, ExactSpelling:=True)> _

  Friend Shared Function GdipDrawString(ByVal graphics As IntPtr, _

                       ByVal textString As String, _

                       ByVal length As Integer, _

                       ByVal font As IntPtr, _

                       ByRef layoutRect As GPRECTF, _

                       ByVal stringFormat As IntPtr, _

                       ByVal brush As IntPtr) As Integer

  End Function

  <StructLayout(LayoutKind.Sequential)> _

  Friend Structure GPRECTF

    Friend X As Single

    Friend Y As Single

    Friend Width As Single

    Friend Height As Single

    Friend Sub New(ByVal x As Single, ByVal y As Single, ByVal width As Single, ByVal height As Single)

      Me.X = x

      Me.Y = y

      Me.Width = width

      Me.Height = height

    End Sub

    Friend Sub New(ByVal rect As RectangleF)

      Me.X = rect.X

      Me.Y = rect.Y

      Me.Width = rect.Width

      Me.Height = rect.Height

    End Sub

    Friend ReadOnly Property SizeF() As SizeF

      Get

        Return New SizeF(Me.Width, Me.Height)

      End Get

    End Property

    Friend Function ToRectangleF() As RectangleF

      Return New RectangleF(Me.X, Me.Y, Me.Width, Me.Height)

    End Function

  End Structure

  Public Sub Draw4(ByVal Text As String)

    Clear()

    Dim i As Integer, j As Integer, tS() As String

    j = Int(Text.Length / 52)

    ReDim tS(j - 1)

    For i = 0 To j - 1

      tS(i) = Text.Substring(i * 52, 52)

    Next

    If Text.Length - j * 52 <> 0 Then

      ReDim Preserve tS(j+1)

      tS(j+1) = Text.Substring(j * 52)

    End If

    DrawLineText(mG, tS, mFont, New SolidBrush(mForeColor))

  End Sub

  Private Sub DrawLineText(ByVal G As Graphics, ByVal T() As String, ByVal F As Font, ByVal B As Brush)

    If (G Is Nothing) Then Throw New ArgumentNullException("graphics")

    If (T Is Nothing) Then Throw New ArgumentNullException("text")

    If (F Is Nothing) Then Throw New ArgumentNullException("font")

    If (B Is Nothing) Then Throw New ArgumentNullException("brush")

    Dim Field As FieldInfo

    Field = GetType(Graphics).GetField("nativeGraphics", BindingFlags.Instance Or BindingFlags.NonPublic)

    Dim hGraphics As IntPtr = Field.GetValue(G)
    Field = GetType(Font).GetField("nativeFont", BindingFlags.Instance Or BindingFlags.NonPublic)

    Dim hFont As IntPtr = Field.GetValue(F)

    Field = GetType(Brush).GetField("nativeBrush", BindingFlags.Instance Or BindingFlags.NonPublic)

    Dim hBrush As IntPtr = Field.GetValue(B)

    Dim i As Integer, tR As GPRECTF

    tR = New GPRECTF(0, 0, mBmp.Width, mBmp.Height)

    For i = 0 To 17

      tR.X = 3

      tR.Y = 3 + i * mLineHeight

      GdipDrawString(hGraphics, T(i), T(i).Length, hFont, tR, IntPtr.Zero, hBrush)

    Next

  End Sub

  经测试,方法四和方法三的效率不相上下。但是,方法四更接近我们直观的想法,而且对Font的要求也不是很高。

  可能还有更好的方法,欢迎各位网友交流。

posted @ 2010-04-22 09:14  万仓一黍  阅读(3056)  评论(1编辑  收藏  举报