为C#设计一个自定义字体对话框/选择器,过滤掉非TrueType字体。

9

由于内置的字体对话框在选择非True Type字体时会返回“Not a True Type Font”异常,因此我正在尝试使用字体系列创建自定义字体对话框,以过滤掉非True Type字体。

该控件运作正常,但我需要为该对话框添加大小和样式选择器。我正在发布当前代码。请帮助我添加大小和样式选择器,这也可能对您有所帮助。

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);
    }
}

public partial class MyFontDialog : Form
{
    private FontListBox _fontListBox;

    public MyFontDialog()
    {
        InitializeComponent();

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

我已将该项目托管在sourceforge上https://sourceforge.net/p/newfontpicker/


FontDialog类已经过滤了非TrueType字体。真正的解决方案是卸载具有不良元数据的字体。 - Hans Passant
请参阅 http://c-madeeasy.blogspot.com/2011/11/unsolved-this-is-not-true-type-font.html。 - techno
它试图过滤这些opentype字体,但仍然存在一些字体。请参见http://connect.microsoft.com/VisualStudio/feedback/details/708872/this-is-not-a-true-type-font-only-true-type-fonts-are-accepted-exception。 - techno
3个回答

1
你可以像这样修改 MyFontDialog:
public partial class MyFontDialog : Form
{
    private FontListBox _fontListBox;
    private ListBox _fontSizeListBox;

    public MyFontDialog()
    {
        //InitializeComponent();

        _fontListBox = new FontListBox();
        _fontListBox.SelectedIndexChanged += OnfontListBoxSelectedIndexChanged;
        _fontListBox.Size = new Size(200, Height);
        Controls.Add(_fontListBox);

        _fontSizeListBox = new ListBox();
        _fontSizeListBox.Location = new Point(_fontListBox.Width, 0);

        Controls.Add(_fontSizeListBox);
    }

    private void OnfontListBoxSelectedIndexChanged(object sender, EventArgs e)
    {
        _fontSizeListBox.Items.Clear();
        Font font = _fontListBox.SelectedItem as Font;
        if (font != null)
        {
            foreach (FontStyle style in Enum.GetValues(typeof(FontStyle)))
            {
                if (font.FontFamily.IsStyleAvailable(style))
                {
                    _fontSizeListBox.Items.Add(style);
                }
            }
        }
    }
}

它将创建一个列表框,旁边是字体列表框,其中列出可用的字体样式。至于尺寸选择,您可以添加一个列表框,其硬编码大小列表为:8、9、10、11、12、14、16、18、20、22、24、26、28、36、48 和 72,就像标准的 FontDialog 一样,因为我们正在处理真正的字体。


0

好的,Umar, 你应该尝试:

1)使用“FontFamily.IsStyleAvailable”来避免/最小化需要捕获异常的情况 - 从而错过一些可用的字体。 2)通过Graphics.MeasureString进行一些调整,为每个单独的字体设置一个看起来最好且可以让你获得等高列的大小...

祝你好运 :)

Jens,丹麦。


0

http://www.developerfusion.com/code/254/determine-if-a-font-is-truetype/提供了一些VB代码来确定字体是否为TT字体。它实际上只是调用了一些Win32 API函数并检查结果。

可能会有一些看起来像TT字体但实际上不是的字体,即使使用Win32 API进行检查(FontDialog可能正在执行此操作)。如果Win32无法解决您的问题,则可能唯一的方法是检查异常以查找无效字体。


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