在上文“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的要求也不是很高。
可能还有更好的方法,欢迎各位网友交流。