Правильно рисовать текст с помощью графического контура
Как вы можете видеть на изображении ниже, текст в окне рисунка отличается от текста в окне. Это работает хорошо, если я использую Graphics.DrawString()
но когда я использую Графический путь, он усекается и не показывает весь текст. Что вы думаете не так в моем коде?
Вот мой код:
public LayerClass DrawString(LayerClass.Type _text, string text, RectangleF rect, Font _fontStyle, PaintEventArgs e)
{
using (StringFormat string_format = new StringFormat())
{
rect.Size = e.Graphics.MeasureString(text, _fontStyle);
rect.Location = new PointF(Shape.center.X - (rect.Width / 2), Shape.center.Y - (rect.Height / 2));
if(isOutlinedOrSolid)
{
using (GraphicsPath path = new GraphicsPath())
{
path.AddString(text, _fontStyle.FontFamily, (int)_fontStyle.Style, rect.Size.Height, rect, string_format);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
e.Graphics.DrawPath(new Pen(Color.Red, 1), path);
}
}
else
{
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
e.Graphics.DrawString(text,_fontStyle,Brushes.Red, rect.Location);
}
}
this._Text = text;
this._TextRect = rect;
return new LayerClass(_text, this, text, rect);
}
2 ответа
Похоже, вы вначале указали неправильный размер шрифта, а затем добавили дополнительную толщину кисти. Попробуйте это вместо этого:
using (GraphicsPath path = new GraphicsPath())
{
path.AddString(
text,
_fontStyle.FontFamily,
(int)_fontStyle.Style,
e.Graphics.DpiY * fontSize / 72f, // em size
new Point(0, 0), // location where to draw text
string_format);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
e.Graphics.DrawPath(new Pen(Color.Red), path);
}
Класс GraphicsPath вычисляет размер объекта Text другим способом (как уже отмечалось в комментариях). Размер текста рассчитывается с использованием Ems
размер ограничительного прямоугольника.Em
типографская мера, которая не зависит от контекста устройства назначения.
Это относится к прямоугольнику, занимаемому самой широкой буквой шрифта, обычно буквой "М" (произносится как em).
Пункт назначения Em
Размер можно рассчитать двумя разными способами: один включает Font
descent
другой не включает его. Последнее чаще встречается (так как "М" не имеет descent
части).
float EMSize = (Font.Height * [FontFamly].GetCellAscent([FontStyle])
/ [FontFamily].GetEmHeight([FontStyle]
или же
float EMSize = (Font.Height * ([FontFamly].GetCellAscent([FontStyle] +
[FontFamily.GetCellDescent([FontStyle]))
/ [FontFamily].GetEmHeight([FontStyle]
Смотрите документы о:
FontFamily.GetEmHeight, FontFamily.GetCellAscent и FontFamily.GetCellDescent
Я вставляю сюда рисунок, который вы можете найти в Документах.
Обратитесь к общей информации, содержащейся здесь:
Использование шрифта и текста (MSDN)
В этом документе рассказывается о том, как переводить очки, пиксели и символы:
Как получить метрику шрифта (MSDN)
Я предполагаю, что у вас уже есть объект класса, который содержит / ссылается на настройки шрифта, которые поступают из элементов управления пользовательского интерфейса и необходимых настроек.
Я добавляю один здесь с некоторыми свойствами, которые содержат подмножество этих настроек, связанных с вопросом.
Этот класс выполняет некоторые вычисления на основе размера шрифта, выбранного пользователем.
Размер шрифта обычно указывается в Points
, Эта мера затем преобразуется в Pixels
, используя текущий экран DPI
разрешение (или преобразуется в Points
из Pixel
измерение). Каждая мера также преобразуется в Ems
, который пригодится, если вам придется использовать GraphicsPath
нарисовать текст.
Ems
размер рассчитывается с учетом как Ascent
и Descent
шрифта. GraphicsPath
лучше работает с этой мерой, так как смешанный текст может иметь обе части, а если нет, то эта часть = 0.
Чтобы вычислить контейнерное поле текста, нарисованного с определенным размером шрифта и шрифта, используйте метод GraphicsPath.GetBounds():
([Canvas]
это контроль, который обеспечивает Paint
События e.Graphics
объект)
using (GraphicsPath path = new GraphicsPath())
using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
{
format.Alignment = [StringAlignment.Center/Near/Far]; //As selected
format.LineAlignment = [StringAlignment.Center/Near/Far]; //As selected
//Add the Text to the GraphicsPath
path.AddString(fontObject.Text, fontObject.FontFamily,
(int)fontObject.FontStyle, fontObject.SizeInEms,
[Canvas].ClientRectangle, format);
//Ems size (bounding rectangle)
RectangleF TextBounds = path.GetBounds(null, fontObject.Outline);
//Location of the Text
fontObject.Location = TextBounds.Location;
}
Нарисуйте текст на [Canvas]
Контекст устройства:
private void Canvas_Paint(object sender, PaintEventArgs e)
{
using (GraphicsPath path = new GraphicsPath())
using (StringFormat format = new StringFormat(StringFormatFlags.NoClip | StringFormatFlags.NoWrap))
{
format.Alignment = [StringAlignment.Center/Near/Far]; //As selected
format.LineAlignment = [StringAlignment.Center/Near/Far]; //As selected
path.AddString(fontObject.Text, fontObject.FontFamily, (int)fontObject.FontStyle, fontObject.SizeInEms, Canvas.ClientRectangle, format);
e.Graphics.SmoothingMode = SmoothingMode.AntiAlias;
e.Graphics.CompositingMode = CompositingMode.SourceOver;
e.Graphics.CompositingQuality = CompositingQuality.HighQuality;
e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
if (fontObject.Outlined) {
e.Graphics.DrawPath(fontObject.Outline, path);
}
using(SolidBrush brush = new SolidBrush(fontObject.FillColor)) {
e.Graphics.FillPath(brush, path);
}
}
}
Визуальный эффект с использованием этого класса и реализуемых методов:
Объект класса, чтобы использовать в качестве ссылки:
public class FontObject
{
private float CurrentScreenDPI = 0.0F;
private float m_SizeInPoints = 0.0F;
private float m_SizeInPixels = 0.0F;
public FontObject()
: this(string.Empty, FontFamily.GenericSansSerif, FontStyle.Regular, 18F) { }
public FontObject(string Text, Font font)
: this(Text, font.FontFamily, font.Style, font.SizeInPoints) { }
public FontObject(string Text, FontFamily fontFamily, FontStyle fontStyle, float FontSize)
{
if (FontSize < 3) FontSize = 3;
using (Graphics g = Graphics.FromHwndInternal(IntPtr.Zero)) {
this.CurrentScreenDPI = g.DpiY;
}
this.FontFamily = fontFamily;
this.SizeInPoints = FontSize;
this.FillColor = Color.White;
this.Outline = new Pen(Color.Black, 1);
this.Outlined = false;
}
public string Text { get; set; }
public FontStyle FontStyle { get; set; }
public FontFamily FontFamily { get; set; }
public Color FillColor { get; set; }
public Pen Outline { get; set; }
public bool Outlined { get; set; }
public float SizeInPoints {
get => this.m_SizeInPoints;
set { this.m_SizeInPoints = value;
this.m_SizeInPixels = (value * 72F) / this.CurrentScreenDPI;
this.SizeInEms = GetEmSize();
}
}
public float SizeInPixels {
get => this.m_SizeInPixels;
set { this.m_SizeInPixels = value;
this.m_SizeInPoints = (value * this.CurrentScreenDPI) / 72F;
this.SizeInEms = GetEmSize();
}
}
public float SizeInEms { get; private set; }
public PointF Location { get; set; }
public RectangleF DrawingBox { get; set; }
private float GetEmSize()
{
return (this.m_SizeInPoints *
(this.FontFamily.GetCellAscent(this.FontStyle) +
this.FontFamily.GetCellDescent(this.FontStyle))) /
this.FontFamily.GetEmHeight(this.FontStyle);
}
}
редактировать
ComboBox с семействами шрифтов.
Настроить OwnerDraw
ComboBox
:
string[] FontList = FontFamily.Families.Where(f => f.IsStyleAvailable(FontStyle.Regular)).Select(f => f.Name).ToArray();
cboFontFamily.DrawMode = DrawMode.OwnerDrawVariable;
cboFontFamily.AutoCompleteMode = AutoCompleteMode.SuggestAppend;
cboFontFamily.AutoCompleteSource = AutoCompleteSource.CustomSource;
cboFontFamily.AutoCompleteCustomSource.AddRange(FontList);
cboFontFamily.DisplayMember = "Name";
cboFontFamily.Items.AddRange(FontList);
cboFontFamily.Text = "Arial";
Обработчики событий:
private void cboFontFamily_DrawItem(object sender, DrawItemEventArgs e)
{
TextFormatFlags flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
using (FontFamily family = new FontFamily(cboFontFamily.GetItemText(cboFontFamily.Items[e.Index])))
using (Font font = new Font(family, 10F, FontStyle.Regular, GraphicsUnit.Point)) {
TextRenderer.DrawText(e.Graphics, family.Name, font, e.Bounds, cboFontFamily.ForeColor, flags);
}
e.DrawFocusRectangle();
}
private void cboFontFamily_MeasureItem(object sender, MeasureItemEventArgs e)
{
e.ItemHeight = (int)this.Font.Height + 4;
}
private void cboFontFamily_SelectionChangeCommitted(object sender, EventArgs e)
{
fontObject.FontFamily = new FontFamily(cboFontFamily.GetItemText(cboFontFamily.SelectedItem));
Canvas.Invalidate();
}