2

好的,我正在解决在文本框中嵌入 LCD 类型 True Type 字体的问题。至于一些背景,如果我将字体安装到我的系统上,我可以显示 lcd 字体,然后将其加载为文本框的字体类型,效果很好。但是,它不能作为应用程序中的嵌入字体。我正在使用 Visual Basic 中的 Windows 窗体应用程序,来自 Windows 7 机器上的 Microsoft Visual Studio 2010。

在将字体存储为资源文件并将属性设置为嵌入资源之后,我使用内存中的私有字体集合尝试了以下代码。

Imports System.Drawing.Text

Imports System.Runtime.InteropServices

Module CustomFont

'PRIVATE FONT COLLECTION TO HOLD THE DYNAMIC FONT

Private _pfc As PrivateFontCollection = Nothing

Public ReadOnly Property GetInstance(ByVal Size As Single, _

                                     ByVal style As FontStyle) As Font

    Get

        'IF THIS IS THE FIRST TIME GETTING AN INSTANCE

        'LOAD THE FONT FROM RESOURCES

        If _pfc Is Nothing Then LoadFont()

        'RETURN A NEW FONT OBJECT BASED ON THE SIZE AND STYLE PASSED IN

        Return New Font(_pfc.Families(0), Size, style)


    End Get

End Property



Private Sub LoadFont()

    Try

        'INIT THE FONT COLLECTION

        _pfc = New PrivateFontCollection



        'LOAD MEMORY POINTER FOR FONT RESOURCE

        Dim fontMemPointer As IntPtr = _

            Marshal.AllocCoTaskMem( _

            My.Resources.DIGITALDREAMNARROW.Length)



        'COPY THE DATA TO THE MEMORY LOCATION

        Marshal.Copy(My.Resources.DIGITALDREAMNARROW, _

                     0, fontMemPointer, _

                     My.Resources.DIGITALDREAMNARROW.Length)



        'LOAD THE MEMORY FONT INTO THE PRIVATE FONT COLLECTION

        _pfc.AddMemoryFont(fontMemPointer, _

                           My.Resources.DIGITALDREAMNARROW.Length)


        'FREE UNSAFE MEMORY

        Marshal.FreeCoTaskMem(fontMemPointer)

    Catch ex As Exception

        'ERROR LOADING FONT. HANDLE EXCEPTION HERE

    End Try


End Sub

End Module

此代码的问题在于您应该将控件的 UseCompatibleTextRendering 属性启用为 true。如果在标签或按钮文本上使用此模块,则效果很好。但是,对于文本框,没有 UseCompatibleTextRendering 属性。

我开始明白文本框使用 GDI 渲染,而其他文本控件使用 GDI+(我可能已经切换了那些,所以不要引用我的话,我只记得它们是不同的)。

我发现一些较旧的代码片段尝试使用 Windows 中 gdi32.dll 文件中的 AddFontMemResourceEX 函数,有些人声称它可以在文本框中使用。所以我创建了以下课程。

Imports System
Imports System.Drawing.Text
Imports System.IO
Imports System.Reflection

Public Class GetLCDFont
Private Declare Auto Function AddFontMemResourceEX Lib "gdi32.dll" _
    (ByVal pbFont As Integer, ByVal cbFont As Integer, _
     ByVal pdv As Integer, ByRef pcFonts As Integer) As IntPtr

Public Shared Function GetFont(ByVal fontName As String) As FontFamily

    Dim exeCurrent As [Assembly] = [Assembly].GetExecutingAssembly()
    Dim nameSpc As String = exeCurrent.GetName().Name.ToString()
    Dim fontCollection As New PrivateFontCollection
    Dim loadStream As Stream = exeCurrent.GetManifestResourceStream( _
        nameSpc + "." + fontName)
    Dim byteBuffer(CType(loadStream.Length, Integer)) As Byte

    loadStream.Read(byteBuffer, 0, Int(CType(loadStream.Length, Integer)))

    Dim fontPtr As IntPtr = Runtime.InteropServices.Marshal.AllocHGlobal( _
        Runtime.InteropServices.Marshal.SizeOf(GetType(Byte)) * _
        byteBuffer.Length)

    Runtime.InteropServices.Marshal.Copy(byteBuffer, 0, fontPtr, byteBuffer.Length)

    fontCollection.AddMemoryFont(fontPtr, byteBuffer.Length)

    Dim pcFonts As Int32 = 1

    AddFontMemResourceEX(fontPtr, byteBuffer.Length, 0, pcFonts)

    Runtime.InteropServices.Marshal.FreeHGlobal(fontPtr)
    Return fontCollection.Families(0)

End Function

Public Sub New()

End Sub

Protected Overrides Sub Finalize()
    MyBase.Finalize()
End Sub
End Class

然而,当调用这个类时,我得到一个 InvalidOperationException 未处理。错误是无法在 DLL 'gdi32.dll' 中找到一个名为 'AddFontMemResourceEX' 的条目。

希望有人可以帮助我告诉我哪里出了问题,或者指出一个方向,以帮助我在文本框中嵌入字体以与 Windows 窗体应用程序一起使用。

MSDN 中引用的大多数示例都指向如何在使用 WPF 应用程序时打包字体。

谢谢你。

4

2 回答 2

0

我一直在使用上面的代码作为标签,但从未尝试过使用文本框。

您可以创建一个继承自 Textbox 的自定义文本框类,然后重写 WndProc 方法,因为 OnPaint 不会呈现文本。

Public Class CustomTextBox
  Inherits TextBox

  Public Const WM_NCPAINT As Integer = &H85

  <DllImport("User32.dll")> _
  Public Shared Function GetWindowDC(ByVal hWnd As IntPtr) As IntPtr
  End Function

  <DllImport("user32.dll")> _
  Private Shared Function ReleaseDC(ByVal hWnd As IntPtr, ByVal hDC As IntPtr) As Boolean
  End Function

  Protected Overrides Sub WndProc(ByRef m As Message)
    MyBase.WndProc(m)

    If m.Msg = WM_NCPAINT Then
      Dim hDC As IntPtr = GetWindowDC(m.HWnd)
      Using g As Graphics = Graphics.FromHdc(hDC)
        g.DrawString(Me.Text, GetInstance(10, FontStyle.Bold), New SolidBrush(Me.ForeColor), Me.ClientRectangle)
      End Using
      ReleaseDC(m.HWnd, hDC)
    End If

  End Sub
End Class
于 2013-02-24T01:42:31.367 回答
0

虽然它不是很干净,但您可以使用安装程序将字体放在应用程序目录中,然后使用以下方法将它们加载到 PrivateFontCollection 中:

    For Each fontfile As String In System.IO.Directory.GetFiles(filepath & "\Fonts", "*.ttf")
        _pfc.AddFontFile(fontfile)
    Next fontfile

我不知道为什么微软会以不同的方式对待它,但我的 TextBoxes 和 ComboBoxes 现在使用我的自定义字体,即使它们没有 UseCompatibleTextRendering 属性。

于 2015-05-19T19:19:49.940 回答