如何将privatefontcollection内存中的字体呈现为可编辑的控件

时间:2015-10-14 03:00:35

标签: c# winforms gdi+ gdi privatefontcollection

这是Loading a font from resources into PrivateFontCollection results in corruption

的延续

提供的答案here对于UseCompatibleTextRendering方法可用的控件已足够,但它似乎不适用于其他常用控件,其中文本是主要关注点,例如:

  • 的ListView
  • 文本框
  • RichTextBox的
  • 组合框
  • ......还有更多......

我尝试了来自here的信息,该信息基本上是用Application.SetCompatibleTextRenderingDefault中的Program.cs行进行操作(没有人明确说明此设置在哪里,所以我在这里记录它)。我也玩过Telerik,DevExpress和Infragistics文本控件,除了Telerik之外没有内置兼容文本渲染的能力.Teleriks控件有这个方法,但它没有效果,包括无法将forecolor设置为存储的内容在属性中(一种不同的动物,只是注意到Telerik radTextBox控件的毛刺)。

无论我如何对其进行切片,任何对文本实际有用的控件都不会使文本正确显示上面提到的原始帖子中描述的方形字符。

总结:

  • 字体从资源加载到内存到PrivateFontCollection
  • 应用程序不会崩溃
  • 标签上成功使用相同的字体(UseCompatibleTextRendering对它们起作用) - 在同一个表单上,在同一个项目中。

  • 受此(新?)问题影响的控件严格来说是任何可以“键入”的控件,如TextEdit,ListView,RichText,Combo等

  • 当谈到切换,玩弄或玩耍时 - 这意味着我尝试了所提供的所有控件和/或代码的所有可能组合。例如:Application.SetCompatibleTextRenderingDefault本身只有3种可能的组合。 (true) (false)或完全省略。完成这3个组合之后,我接着进行了(基本故障排除,但我发现有必要解释所有基础)添加Telerik控件,然后尝试Telerik控件中的所有组合,并结合{{的所有组合1}}命令。测试的数量是指数级的,即渲染可能性的可能组合的数量乘以尝试的控制的数量乘以每个控件具有的渲染控制的可能性的数量,等等。

1 个答案:

答案 0 :(得分:7)

经过大量的挖掘,并且在这个问题上空洞了(包括对这个仍然让我困惑的问题的驱逐者),我找到了一个解决这个问题的方法,它似乎已经面临许多问题并且也来了空手而归只是将字体安装为用户系统上的文件。正如我想的那样,这根本不是必需的,你可以用一种简单的方式嵌入字体,这样就可以在任何控件上使用它,包括TextBox,ComboBox等。无论你想要什么。

我将把这篇文章作为一步一步的指南来编写如何将字体嵌入到项目中并使其在任何您想要的控件上正确显示。

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

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

  • 在项目内,转到Project > <your project name> Properties
  • 点击Resources(应位于左侧)
  • 点击Add Resource按钮右侧的下拉箭头,然后选择Add Existing File

enter image description here

  • 确保从下拉列表中选择All Files (*.*),然后浏览到要嵌入字体文件的位置,选择它,然后单击[打开]按钮。 enter image description here

您现在应该看到如下内容: enter image description here

  • 按[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控件 enter image description here

  • 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" );
    }
    

最终结果

enter image description here

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

时使用适当的索引值(基于零)

与有关Microsoft PrivateFontCollection.AddMemoryFont()文档的文档相反,您根本不需要使用UseCompatibleTextRenderingSetCompatibleTextRenderingDefault。上面概述的方法允许在对象/控件中自然呈现字体。