Как отобразить шрифт из памяти privatefontcollection в редактируемые элементы управления
Это продолжение загрузки шрифта из ресурсов в PrivateFontCollection приводит к повреждению
Ответ, приведенный здесь, достаточен для элементов управления, которые имеют UseCompatibleTextRendering
доступный метод, однако он не доступен для других общих элементов управления, основным текстом которых является:
- Посмотреть список
- Текстовое окно
- RichTextBox
- Поле со списком
- ... и многое другое...
Я попытался информацию отсюда, которая в основном играет с Application.SetCompatibleTextRenderingDefault
линия в Program.cs
(никто не уточнил, где этот параметр по умолчанию, поэтому я документирую его здесь). Я также поиграл с текстовыми элементами управления Telerik, DevExpress и Infragistics, все, кроме Telerik, не имеют встроенной функции совместимого рендеринга текста. Элемент управления Teleriks имеет метод, однако он имеет нулевой эффект, включая невозможность установить передний цвет на то, что сохраняется в свойстве (другое животное, просто отметив сбой элемента управления Telerik radTextBox).
Кажется, независимо от того, как я это делю, любой элемент управления, который на самом деле полезен для текста, не будет отображать текст должным образом, отображая квадратные символы, как показано в оригинальном сообщении, указанном выше.
В итоге:
- Шрифт загружается из ресурса в память в PrivateFontCollection
- Приложение не падает
Тот же шрифт успешно используется на ярлыках (с ними работает UseCompatibleTextRendering) - в той же форме, в том же проекте.
Элементы управления, на которые влияет эта (новая?) Проблема, являются строго любыми элементами управления, которые можно потенциально "ввести", такими как TextEdit, ListView, RichText, Combo и т. Д.
Говоря о переключении, игре или игре - это означает, что я пытался использовать все возможные комбинации указанных элементов управления и / или кода, которые были мне предоставлены. Например:
Application.SetCompatibleTextRenderingDefault
имеет только 3 возможных комбинации в себе.(true)
(false)
или полностью опущен. После завершения этих трех комбинаций я продолжил (базовое устранение неполадок здесь, но считаю необходимым объяснить все базы), чтобы добавить элемент управления Telerik, а затем попробовать все комбинации в элементе управления Telerik вместе со всеми комбинациямиApplication.SetCompatibleTextRenderingDefault
команда. Количество тестов является экспоненциальным и представляет собой число возможных комбинаций возможностей рендеринга, умноженное на количество попыток элементов управления, умноженное на количество возможностей для элемента управления рендеринга, которые есть у каждого из этих элементов управления, и так далее.
1 ответ
После долгих раскопок и пустых рассуждений по этому вопросу (в том числе по поводу этого вопроса, который меня до сих пор озадачивает), я нашел решение этой проблемы, с которой, как мне кажется, многие столкнулись, а также оказалось пустым - Вручил прибегнуть к простой установке шрифта в виде файла в системе пользователей. Как я и думал, это вовсе не обязательно, и вы МОЖЕТЕ встроить шрифт простым способом, который позволяет использовать его на любом элементе управления, включая TextBox, ComboBox и т. Д. Все, что пожелает ваше сердце.
Я напишу это как пошаговое руководство о том, как встроить шрифт в ваш проект и правильно ли он отображать его на любом элементе управления, который вы пожелаете.
Шаг 1 - Выбор жертвы (выбор шрифта)
Для демонстрационных целей (и популярного спроса) я буду использовать шрифт FontAwesome (v 4.1 на момент написания этой статьи)
- Внутри вашего проекта, перейдите к
Project > <your project name> Properties
- Нажмите
Resources
(должно быть на левой стороне) - Нажмите стрелку раскрывающегося меню справа от
Add Resource
и выберитеAdd Existing File
,
- Убедитесь, что
All Files (*.*)
В раскрывающемся списке выберите нужный файл шрифта и выберите его, затем нажмите кнопку [Открыть].
Теперь вы должны увидеть что-то вроде следующего:
- Нажмите [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) [] // so I pass 'f1b9' to my UnicodeToChar method which returns the Automobile icon textBox1.Text = MemoryFonts.UnicodeToChar( "f1b9" ); }
Конечный результат
Вы можете заметить или не заметить, что я создал этот метод, имея в виду, что вы можете добавить несколько встроенных шрифтов. В этом случае вы просто позвоните AddMemoryFont()
для каждого из шрифтов, которые вы хотите добавить, а затем используйте соответствующее значение индекса (на основе нуля) при использовании GetFont()
Вопреки документу, касающемуся документации PrivateFontCollection.AddMemoryFont() от Microsoft, вам НЕ НУЖНО использовать UseCompatibleTextRendering
или же SetCompatibleTextRenderingDefault
совсем. Метод, который я описал выше, позволяет естественную визуализацию шрифта в объектах / элементах управления.