如何从 privatefontcollection 内存中渲染字体到可编辑控件

How to render a font from privatefontcollection memory to editable controls

这是

的延续

提供的答案 对于具有 UseCompatibleTextRendering 方法可用的控件来说已经足够了,但是它似乎不适用于其他以文本为主要焦点的常见控件,例如:

我尝试了来自 here 的信息,这些信息基本上是在玩弄 Program.cs 中的 Application.SetCompatibleTextRenderingDefault 行(没有人说明默认设置在哪里,所以我在这里记录它).我还玩过 Telerik、DevExpress 和 Infragistics 文本控件,除了 Telerik 之外,所有控件都没有内置兼容文本呈现的能力。Teleriks 控件有这个方法,但是它的效果为零,包括无法将前景色设置为存储的内容在 属性(另一种动物,只是注意到 Telerik radTextBox 控件的故障)。

似乎无论我如何分割它,任何实际对文本有用的控件都不会呈现正确显示方块字符的文本,如上面提到的原始 post 中所述。

总结:

经过大量的挖掘,并在这个问题上一无所获(包括对这个问题的 drive-by 否决,这仍然让我感到困惑),我找到了这个问题的解决方案,似乎很多人都面临过并且还提出 empty-handed 求助于将字体作为文件安装在用户系统上。正如我所想,这根本不是必需的,您可以以一种简单的方式嵌入字体,这允许它在 any 控件上使用,包括 TextBox、ComboBox 等。随心所欲.

我将把它写成一个步骤 by-step 指南,介绍如何将字体嵌入到您的项目中并使其在您需要的任何控件上正确显示。

第 1 步 - 选择你的受害者(字体选择)

出于演示目的(和大众需求),我将使用 FontAwesome 字体(撰写本文时为 v 4.1)

  • 在您的项目中,转到 Project > <your project name> Properties
  • 点击Resources(应该在左边)
  • 单击 Add Resource 按钮右侧的下拉箭头,然后 select Add Existing File

  • 确保 All Files (*.*) 已从下拉菜单中 select 编辑,然后浏览到您希望嵌入字体文件的位置,select 它,然后单击 [打开] 按钮。

您现在应该会看到如下内容:

  • 按 [CTRL]+[S] 保存项目。

第 2 步 - 深入研究代码

复制以下代码并将其另存为'MemoryFonts.cs'然后将其添加到您的项目

using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;

using System.Runtime.InteropServices;
using System.Drawing.Text;
using System.Drawing;

public static class MemoryFonts {

    [DllImport( "gdi32.dll" )]
    private static extern IntPtr AddFontMemResourceEx( IntPtr pbFont, uint cbFont, IntPtr pdv, [In] ref uint pcFonts );
    private static PrivateFontCollection pfc { get; set; }

    static MemoryFonts() {
        if ( pfc==null ) { pfc=new PrivateFontCollection(); }
    }

    public static void AddMemoryFont(byte[] fontResource) {
        IntPtr p;
        uint c = 0;

        p=Marshal.AllocCoTaskMem( fontResource.Length );
        Marshal.Copy( fontResource, 0, p, fontResource.Length );
        AddFontMemResourceEx( p, (uint)fontResource.Length, IntPtr.Zero, ref c );
        pfc.AddMemoryFont( p, fontResource.Length );
        Marshal.FreeCoTaskMem( p );

        p = IntPtr.Zero;
    }

    public static Font GetFont( int fontIndex, float fontSize = 20, FontStyle fontStyle = FontStyle.Regular ) {
        return new Font(pfc.Families[fontIndex], fontSize, fontStyle);
    }

    // Useful method for passing a 4 digit hex string to return the unicode character
    // Some fonts like FontAwesome require this conversion in order to access the characters
    public static string UnicodeToChar( string hex ) {
        int code=int.Parse( hex, System.Globalization.NumberStyles.HexNumber );
        string unicodeString=char.ConvertFromUtf32( code );
        return unicodeString;
    }

}

第 3 步 - 使其美观(使用字体)

  • 在主窗体上,从工具箱中添加一个 TextBox 控件

  • form_Load 事件中,放入以下代码(在我的例子中,资源是 fontawesome_webfont。将其更改为您命名的任何字体资源)

    private void Form1_Load( object sender, EventArgs e ) {
        MemoryFonts.AddMemoryFont( Properties.Resources.fontawesome_webfont );
        textBox1.Font = MemoryFonts.GetFont(
                            // using 0 since this is the first font in the collection
                            0,
    
                            // this is the size of the font
                            20, 
    
                            // the font style if any. Bold / Italic / etc
                            FontStyle.Regular
                        );
    
        // since I am using FontAwesome, I would like to display one of the icons
        // the icon I chose is the Automobile (fa-automobile). Looking up the unicode
        // value using the cheat sheet https://fortawesome.github.io/Font-Awesome/cheatsheet/
        // shows :  fa-automobile (alias) [&#xf1b9;]
        // so I pass 'f1b9' to my UnicodeToChar method which returns the Automobile icon 
        textBox1.Text = MemoryFonts.UnicodeToChar( "f1b9" );
    }
    

最终结果


您可能注意到也可能没有注意到我制作此方法时请记住您可能希望添加多种嵌入字体。在这种情况下,您只需为每个要添加的字体调用 AddMemoryFont(),然后在使用 GetFont()

时使用适当的索引值(从零开始)

与 Microsoft 关于 PrivateFontCollection.AddMemoryFont() 的文档相反,您根本不需要使用 UseCompatibleTextRenderingSetCompatibleTextRenderingDefault。我上面概述的方法允许在 objects/controls.

中自然呈现字体