简体   繁体   English

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

[英]How to render a font from privatefontcollection memory to editable controls

This is a continuation of Loading a font from resources into PrivateFontCollection results in corruption 这是将资源从资源加载到PrivateFontCollection导致损坏的延续

The answer supplied here is sufficient for controls that have the UseCompatibleTextRendering method available, however it does not appear to be available for other common controls which text is the primary focus such as : 这里提供的答案足以用于具有UseCompatibleTextRendering方法的控件,但是它似乎不适用于其他常见控件,其中文本是主要焦点,例如:

  • ListView 列表显示
  • TextBox 文本框
  • RichTextBox RichTextBox的
  • ComboBox 组合框
  • ... and many more... ... 还有很多...

I have attempted the information from here which is basically toying with the Application.SetCompatibleTextRenderingDefault line in Program.cs (no one clarified where this setting is by default so I am documenting it here). 我已经尝试过这里的信息,这些信息基本上是用Program.csApplication.SetCompatibleTextRenderingDefault行进行的(没有人明白这个设置是默认的,所以我在这里记录它)。 I have also played around with Telerik, DevExpress, and Infragistics text controls, all except Telerik do not have the ability for compatible text rendering built in. Teleriks control has the method, however it has zero effect including failure to set forecolor to what is stored in the property (a different animal, just noting the glitchiness of the Telerik radTextBox control). 我也玩过Telerik,DevExpress和Infragistics文本控件,除了Telerik之外没有内置兼容文本渲染的能力.Teleriks控件有这个方法,但它没有效果,包括无法将forecolor设置为存储的内容在属性(一个不同的动物,只是注意到Telerik radTextBox控件的毛刺)。

It seems no matter how I slice it, any control that is actually useful with text will not render the text properly displaying the square characters as depicted in the original post noted above. 似乎无论我如何切片,任何对文本实际有用的控件都不会使文本正确显示正方形字符,如上面提到的原始帖子所示。

In summary : 综上所述 :

  • The font is loading from a resource into memory into PrivateFontCollection 字体从资源加载到内存到PrivateFontCollection
  • The application does not crash 应用程序不会崩溃
  • The same font is being used on labels successfully (UseCompatibleTextRendering works on them) - on the same form, in the same project. 成功在标签上使用相同的字体(UseCompatibleTextRendering对它们起作用) - 在同一个表单上,在同一个项目中。

  • The controls that are affected by this (new ?) problem are strictly any control that one can potentially 'type' in such as TextEdit, ListView, RichText, Combo, etc 受此(新?)问题影响的控件严格来说是任何可以“键入”的控件,如TextEdit,ListView,RichText,Combo等。

  • When speaking of toggling, and toying or playing with -- what this means is that I have attempted all possible combinations of said controls and/or code that I have been supplied with. 当谈到切换,玩弄或玩耍时 - 这意味着我已经尝试了所提供的所有控件和/或代码的所有可能组合。 For example: Application.SetCompatibleTextRenderingDefault has only 3 possible combinations in itself. 例如: Application.SetCompatibleTextRenderingDefault本身只有3种可能的组合。 (true) (false) or completely omitted. (true) (false)或完全省略。 After having completed those 3 combinations, I then proceeded (basic troubleshooting here but I find it necessary to explain to cover all bases) to add a Telerik control, then try all combinations in the Telerik control, in conjunction with all combinations of the Application.SetCompatibleTextRenderingDefault command. 在完成这3个组合之后,我接着进行了(基本故障排除,但我发现有必要解释所有基础)添加Telerik控件,然后尝试Telerik控件中的所有组合,以及Application.SetCompatibleTextRenderingDefault所有组合Application.SetCompatibleTextRenderingDefault命令。 The number of tests is exponential being the number of possible combinations of rendering possibilities multiplied by the number of controls attempted multiplied by the number of possibilities for rendering control each of those controls have, and so on. 测试的数量是指数级的,即渲染可能性的可能组合的数量乘以尝试的控制的数量乘以每个控件具有的渲染控制的可能性的数量,等等。

After a lot of digging around, and coming up empty on this (including the drive-by downvote on this question which still puzzles me), I have found a solution to this problem which it seems many have faced and have also come up empty-handed resorting to just installing the font as a file on the users system. 经过大量的挖掘,并在此问题上空洞了(包括仍然困扰我的这个问题的驱动器),我已经找到了解决这个问题的解决方案,它似乎已经面临许多问题并且也出现了问题 - 只需将字体作为文件安装在用户系统上即可。 As I thought, this is not required at all and you CAN embed the font in a simple way which allows it to be used on any control including TextBox, ComboBox, etc. Whatever your heart desires. 正如我想的那样,这根本不是必需的,你可以用一种简单的方式嵌入字体,这样就可以在任何控件上使用它,包括TextBox,ComboBox等。无论你的内心需要什么。

I will write this as a step by-step guide on how to embed a font into your project AND have it display properly on any control you desire. 我将把它作为一步一步的指南来编写,如何将字体嵌入到项目中并使其在您想要的任何控件上正确显示。

Step 1 - Choosing your victim (the font choice) 第1步 - 选择受害者(字体选择)

For demonstration purposes (and popular demand), I will be using the FontAwesome font (v 4.1 at the time of writing this) 出于演示目的(和流行的需求),我将使用FontAwesome字体(在撰写本文时为v 4.1)

  • Inside your project, go to Project > <your project name> Properties 在项目内,转到Project > <your project name> Properties
  • Click Resources (should be on the left side) 单击“ Resources (应位于左侧)
  • Click the dropdown arrow to the right of the Add Resource button, and select Add Existing File . 单击“ Add Resource按钮右侧的下拉箭头,然后选择“ Add Existing File

在此输入图像描述

  • Make sure the All Files (*.*) is selected from the drop down and then browse to where the font file is your wish to embed, select it, and click the [Open] button. 确保从下拉列表中选择All Files (*.*) ,然后浏览到要嵌入的字体文件的位置,选择它,然后单击[打开]按钮。 在此输入图像描述

You should now see something like the following : 您现在应该看到如下内容: 在此输入图像描述

  • Press [CTRL]+[S] to save the project. 按[CTRL] + [S]保存项目。

Step 2 - Diving into the code 第2步 - 潜入代码

Copy the following code and save it as 'MemoryFonts.cs' then add it to your project 复制以下代码并将其另存为“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;
    }

}

Step 3 - Making it pretty (using the font) 第3步 - 使它漂亮(使用字体)

  • On the main form, add a TextBox control from your toolbox 在主窗体上,从工具箱中添加TextBox控件 在此输入图像描述

  • Inside the form_Load event, put the following code (in my case the resource is fontawesome_webfont . change that to whatever your font resource is named) 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" ); } 

The end result 最终的结果

在此输入图像描述


You may or may not have noticed that I made this method keeping in mind that you may wish to add multiple embedded fonts. 您可能会或可能不会注意到我制作此方法时请记住您可能希望添加多个嵌入字体。 In which case, you just call AddMemoryFont() for each of the fonts you want to add, and then use the appropriate index value (zero based) when using GetFont() 在这种情况下,您只需为要添加的每个字体调用AddMemoryFont() ,然后在使用GetFont()时使用适当的索引值(基于零GetFont()

Contrary to the document regarding PrivateFontCollection.AddMemoryFont() 's documentation from Microsoft, you DO NOT NEED to use UseCompatibleTextRendering or SetCompatibleTextRenderingDefault at all. 与Microsoft的UseCompatibleTextRendering ()文档相关的文档相反,您UseCompatibleTextRendering SetCompatibleTextRenderingDefault使用UseCompatibleTextRenderingSetCompatibleTextRenderingDefault The method I outlined above allows for natural rendering of the font in objects/controls. 上面概述的方法允许在对象/控件中自然呈现字体。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM