在C#中的字体对话框中过滤/移除非True Type字体

4
我正在使用字体对话框来选择字体,并使用所选字体创建字体。
font = new Font(fontDialog1.Font.Name, fontDialog1.Font.Size, FontStyle.Regular, GraphicsUnit.Pixel);

当我选择一个非 TrueType 字体时,会出现“这不是 TrueType 字体”的异常。我知道 GDI+ 只支持 TTF。我通过使用 try catch 块来解决了这个问题。但是我该如何配置字体对话框只显示 TTF?


2
它已经以那种方式工作了。卸载那个字体,它的元数据有问题。 - Hans Passant
@UnhandledException 我已经看过这篇帖子了,但问题在那里没有得到解决。那里的答案是卸载非TrueType字体。我不能要求我的用户删除他们安装的字体,因为我的应用程序不支持它们。 - techno
2个回答

2

我认为这个问题没有解决方案(网络上的许多其他文章也是这样说的),但是你可以以某种方式重写 FontDialog 来适应你的需求。

以下是一个实现 FontListBox 的代码,该列表框采用自绘方式显示字体:

enter image description here

下面是一个使用 FontListBox 控件的示例对话框:

public partial class MyFontDialog : Form
{
    private FontListBox _fontListBox;

    public MyFontDialog()
    {
        InitializeComponent();

        _fontListBox = new FontListBox();
        _fontListBox.Dock = DockStyle.Fill;
        Controls.Add(_fontListBox);
    }
}

列表框:

public class FontListBox : ListBox
{
    private List<Font> _fonts = new List<Font>();
    private Brush _foreBrush;

    public FontListBox()
    {
        DrawMode = DrawMode.OwnerDrawFixed;
        ItemHeight = 20;
        foreach (FontFamily ff in FontFamily.Families)
        {
            // determine the first available style, as all fonts don't support all styles
            FontStyle? availableStyle = null;
            foreach (FontStyle style in Enum.GetValues(typeof(FontStyle)))
            {
                if (ff.IsStyleAvailable(style))
                {
                    availableStyle = style;
                    break;
                }
            }

            if (availableStyle.HasValue)
            {
                Font font = null;
                try
                {
                    // do your own Font initialization here
                    // discard the one you don't like :-)
                    font = new Font(ff, 12, availableStyle.Value);
                }
                catch
                {
                }
                if (font != null)
                {
                    _fonts.Add(font);
                    Items.Add(font);
                }
            }
        }
    }

    protected override void Dispose(bool disposing)
    {
        base.Dispose(disposing);
        if (_fonts != null)
        {
            foreach (Font font in _fonts)
            {
                font.Dispose();
            }
            _fonts = null;
        }
        if (_foreBrush != null)
        {
            _foreBrush.Dispose();
            _foreBrush = null;
        }
    }

    public override Color ForeColor
    {
        get
        {
            return base.ForeColor;
        }
        set
        {
            base.ForeColor = value;
            if (_foreBrush != null)
            {
                _foreBrush.Dispose();
            }
            _foreBrush = null;
        }
    }

    private Brush ForeBrush
    {
        get
        {
            if (_foreBrush == null)
            {
                _foreBrush = new SolidBrush(ForeColor);
            }
            return _foreBrush;
        }
    }

    protected override void OnDrawItem(DrawItemEventArgs e)
    {
        base.OnDrawItem(e);
        if (e.Index < 0)
            return;

        e.DrawBackground();
        e.DrawFocusRectangle();
        Rectangle bounds = e.Bounds;
        Font font = (Font)Items[e.Index];
        e.Graphics.DrawString(font.Name, font, ForeBrush, bounds.Left, bounds.Top);
    }
}

如何在此对话框中指定大小和样式(斜体、粗体等)。 - techno
您可以通过代码演示确定FontFamily的可用样式列表。大小可以是一个简单的列表。您需要扩展对话框以处理所有这些扩展,但这是容易的部分。 - Simon Mourier
请问你能帮我添加字体大小和样式选择器吗?问题是列表框在点击事件时返回无效的(字体名称+大小值)字体名称。我该如何从中创建字体? - techno

0

遗憾的是,似乎GDI+无法处理某些字体。简而言之,有两种常见的可缩放字体标准:TrueType和PostScript。它们被合并为OpenType,因此一个OpenType字体可以拥有TT轮廓、PS轮廓或两者兼备。当您要求只在字体选取器中显示TT字体时,即使包含仅包含PS轮廓的OT字体,也会被包括在内。这是因为GDI可以渲染它们,尽管GDI+不能

如果您想创建一个不显示这些字体的字体选择器,您需要找出一种确定支持哪些字体的方法(打开它们并解析它们以查找TT轮廓、尝试使用每个字体并查看是否出现异常,或编写白名单)。然后你需要创建一个仅显示这些字体的字体选择对话框。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接