Designing a Custom Font Dialog/Selector for C# tha

2020-02-01 20:03发布

问题:

Since the inbuilt Font Dialog returns a 'Not a True Type Font' Exception on selecting a Non True Type Font, I'm trying to create a Custom Font Dialog using Font-families which filter out non true type fonts.

The Control is working perfectly but I need a size and style selectors for this dialog. I'm posting the current code. Please help me add a size and a style selector to this. It could also be useful to you.

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

I have hosted the project at sourceforge https://sourceforge.net/p/newfontpicker/

回答1:

You could modify the MyFontDialog like this:

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

It will create a list box aside the font list box with the list of available font styles. As for the size choice, you can simply add a list box with hardcoded list of size: 8,9,10,11,12, 14,16,18,20,22,24,26,28,36,48 and 72, just like the standard FontDialog, since we're dealing with true type fonts.



回答2:

http://www.developerfusion.com/code/254/determine-if-a-font-is-truetype/ has some VB code to determine whether a font is a TT font. All it really does is call some Win32 API functions and examines the results.

There may be some fonts that appear to be TT but aren't, even when examined with the Win32 API (which the FontDialog is probably doing anyway). If Win32 doesn't fix your problem, then probably the only way to find out if a font is invalid is to check for an exception.



回答3:

OK, Umar, You should try:

1) Using the 'FontFamily.IsStyleAvailable' to avoid/minimize the need for catching exceptions -- and thus miss out on some available Fonts. 2) Play a Little with Graphics.MeasureString to set a size for each individual font that looks best AND will get you columns of equal height...

Happy trying :)

Jens, Denmark.