首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >使用GraphicsPath正确绘制文本

使用GraphicsPath正确绘制文本
EN

Stack Overflow用户
提问于 2018-10-30 09:00:24
回答 2查看 3.9K关注 0票数 5

正如您在下面的图片中所看到的,PictureBox上的文本与TextBox中的文本不同。如果我使用Graphics.DrawString(),它可以正常工作,但是当我使用Graphics路径时,它会截断,并且不会显示整个文本。你认为我的代码有什么不对?

这是我的代码:

代码语言:javascript
复制
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);
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2018-10-30 09:45:13

似乎你是提供错误的字体大小在第一位,然后添加额外的厚度到刷子。试一试:

代码语言:javascript
复制
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);
}
票数 5
EN

Stack Overflow用户

发布于 2018-10-31 00:23:12

GraphicsPath类以不同的方式计算文本对象的大小(正如注释中已经指出的那样)。文本大小使用Ems边界矩形大小计算。

Em是一个独立于目标设备上下文的排版度量。

它指的是由字体最宽的字母占据的矩形,通常是字母"M“(发音为em)。

目标Em大小可以通过两种不同的方式计算:一种包括Font descent,另一种不包括它。

代码语言:javascript
复制
float EMSize = (Font.SizeInPoints * [FontFamily].GetCellAscent([FontStyle]) 
                                  / [FontFamily].GetEmHeight([FontStyle])

代码语言:javascript
复制
float EMSize = (Font.SizeInPoints * 
               ([FontFamily].GetCellAscent([FontStyle] + 
                [FontFamily.GetCellDescent([FontStyle])) / 
                [FontFamily].GetEmHeight([FontStyle])

请参阅“文件”:

FontFamily.GetEmHeightFontFamily.GetCellAscentFontFamily.GetCellDescent

我在这里插入你可以在文档中找到的数字。

请参阅此处所载的一般资料:

使用字体和文本(MSDN)

本文件报告了如何翻译点、像素和Ems的具体内容:

如何:获取字体度量(MSDN)

我假设您已经有一个类对象,它包含/引用来自UI控件的字体设置和所需的调整。

我在这里添加一个属性,其中包含与问题相关的这些设置的子集。

此类根据用户选择的字体大小执行某些计算。

字体大小通常以点为单位引用。然后,使用当前屏幕DPI分辨率(或转换为像素维度的点),以像素形式转换此度量值。每个度量都是在Ems中转换的,如果您必须使用GraphicsPath来绘制文本,这是很方便的。

计算Ems大小时考虑到字体的AscentDescent

GraphicsPath类在这个度量中运行得更好,因为混合文本可以同时包含两个部分,如果没有,那么这个部分就是= 0

若要计算使用特定字体和字体大小绘制的文本的容器框,请使用GraphicsPath.GetBounds()方法:

([Canvas]是提供Paint事件的e.Graphics对象的控件)

代码语言:javascript
复制
using (var path = new GraphicsPath())
using (var 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]设备上下文中绘制文本:

代码语言:javascript
复制
private void Canvas_Paint(object sender, PaintEventArgs e)
{
    using (var path = new GraphicsPath())
    using (var 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;
        // When text is rendered directly
        e.Graphics.TextRenderingHint = TextRenderingHint.ClearTypeGridFit;
        // The composition properties are useful when drawing on a composited surface
        // It has no effect when drawing on a Control's plain surface
        e.Graphics.CompositingMode = CompositingMode.SourceOver;
        e.Graphics.CompositingQuality = CompositingQuality.HighQuality;

        if (fontObject.Outlined) { 
            e.Graphics.DrawPath(fontObject.Outline, path);
        }
        using(var brush = new SolidBrush(fontObject.FillColor)) {
            e.Graphics.FillPath(brush, path);
        }
    }
}

使用此类和相关方法的视觉效果:

类对象,用作引用:

代码语言:javascript
复制
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)) {
            currentScreenDPI = g.DpiY; 
        }
        Text = text;
        FontFamily = fontFamily;
        SizeInPoints = FontSize;
        FillColor = Color.Black;
        Outline = new Pen(Color.Black, 1);
        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 => m_SizeInPoints;
        set {  m_SizeInPoints = value;
               m_SizeInPixels = (value * 72F) / currentScreenDPI;
               SizeInEms = GetEmSize();
        }
    }
    public float SizeInPixels {
        get => m_SizeInPixels;
        set {  m_SizeInPixels = value;
               m_SizeInPoints = (value * currentScreenDPI) / 72F;
               SizeInEms = GetEmSize();
        }
    }

    public float SizeInEms { get; private set; }
    public PointF Location { get; set; }
    public RectangleF DrawingBox { get; set; }

    private float GetEmSize()
    {
        return (m_SizeInPoints * 
               (FontFamily.GetCellAscent(FontStyle) +
                FontFamily.GetCellDescent(FontStyle))) /
                FontFamily.GetEmHeight(FontStyle);
    }
}

ComboBox与字体家族

创建自定义ComboBox并设置其DrawMode = OwnerDrawVariable

代码语言:javascript
复制
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";

事件处理程序:

代码语言:javascript
复制
private void cboFontFamily_DrawItem(object sender, DrawItemEventArgs e)
{
    if ((cboFontFamily.Items.Count == 0) || e.Index < 0) return;
    e.DrawBackground();
   
    var flags = TextFormatFlags.Left | TextFormatFlags.VerticalCenter;
    using (var family = new FontFamily(cboFontFamily.GetItemText(cboFontFamily.Items[e.Index])))
    using (var 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();
}
票数 7
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/53060627

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档