Click here to Skip to main content
Click here to Skip to main content

Managed Font Combobox

By , 4 Mar 2005
 

Sample Image - CGFontCombo1.jpg

Introduction

I wrote this code one afternoon when I had some free time. I wanted to see how long it would take me to figure out how to enumerate through all the fonts in the system, then use those fonts to paint the associated entries in a combobox. Having finished the code, I decided the project might make for a good CodeProject article.

Using the code

For the most part, the control should be used like any other .NET custom control. The only thing to keep in mind is that I derived it from System.Windows.Forms.Control instead of System.Windows.Forms.ComboBox, so the properties and events will not be the same as a standard combobox. I made that decision because I felt that if I exposed the collection of combobox items, it would be too hard to manage the list of associated FontFamily objects. Honestly, I had visions of someone adding a non-existent font to the collection and leaving me to deal with the consequences - yuck. :o(

The only event is the 'SelectedIndexChanged' event, which is fired whenever a font name is selected in the combobox.

The only properties of any interest are:

  • The 'SelectedFontFamily' property, which is a runtime property for getting/setting the selected font in the combobox.
  • The 'SelectedIndex' property, which is a runtime property for getting/setting the selected index in the combobox.

To use the control in your code, just drop it on a form, wire up the SelectedIndexChanged event in the Visual Studio event designer, and add some code to respond to changes in the state of the control. Here is a demonstration of the SelectedIndexChanged handler from the sample application:

private void m_fontCombo_SelectedIndexChanged(object sender, System.EventArgs e)
{
    MessageBox.Show(
        this,
        "You selected: " + m_fontCombo.SelectedFontFamily.Name
        );
}

Points of Interest

There are two interesting internal parts to the control. The first is the code used to enumerate through the list of installed fonts:

private void CreateSampleFonts()
{

    // Should we simply exit?
    if (!IsHandleCreated || DesignMode)
        return;

    // Should we destroy any existing sample fonts?
    if (m_comboBox.Items.Count > 0)
    {

        // Loop and cleanup the fonts.
        for (int x = 0; x < m_comboBox.Items.Count; x++)
            ((Font)m_comboBox.Items[x]).Dispose();

        m_comboBox.Items.Clear();

    } // End if we should cleanup the sample fonts.

    // Gets the list of installed fonts.
    FontFamily[] ff = FontFamily.Families;

    // Loop and create a sample of each font.
    for (int x = 0; x < ff.Length; x++)
    {

        System.Drawing.Font font = null;

        // Create the font - based on the styles available.
        if (ff[x].IsStyleAvailable(FontStyle.Regular))
            font = new System.Drawing.Font(
                ff[x].Name, 
                m_comboBox.Font.Size
                );
        else if (ff[x].IsStyleAvailable(FontStyle.Bold))
            font = new System.Drawing.Font(
                ff[x].Name, 
                m_comboBox.Font.Size,
                FontStyle.Bold
                );
        else if (ff[x].IsStyleAvailable(FontStyle.Italic))
            font = new System.Drawing.Font(
                ff[x].Name, 
                m_comboBox.Font.Size,
                FontStyle.Italic
                );
        else if (ff[x].IsStyleAvailable(FontStyle.Strikeout))
            font = new System.Drawing.Font(
                ff[x].Name, 
                m_comboBox.Font.Size,
                FontStyle.Strikeout
                );
        else if (ff[x].IsStyleAvailable(FontStyle.Underline))
            font = new System.Drawing.Font(
                ff[x].Name, 
                m_comboBox.Font.Size,
                FontStyle.Underline
                );

        // Should we add the item?
        if (font != null)
            m_comboBox.Items.Add(font);

    } // End for all the fonts.

} // End CreateSampleFonts()

The FontFamily class makes the enumeration process trivial. Man I love C#! :o)

The second interesting part of the control is the code for actually painting the font entries:

private void m_comboBox_DrawItem(object sender, DrawItemEventArgs e)
{

    // If the index is invalid then simply exit.
    if (e.Index == -1 || e.Index >= m_comboBox.Items.Count)
        return;

    // Draw the background of the item.
    e.DrawBackground();

    // Should we draw the focus rectangle?
    if ((e.State & DrawItemState.Focus) != 0)
        e.DrawFocusRectangle();
    
    Brush b = null;
    
    try
    {

        // Create a new background brush.
        b = new SolidBrush(e.ForeColor);

        // Draw the item.
        e.Graphics.DrawString(
            ((Font)m_comboBox.Items[e.Index]).Name, 
            ((Font)m_comboBox.Items[e.Index]),
            b,
            e.Bounds
            );

    } // End try

    finally
    {

        // Should we cleanup the brush?
        if (b != null)
            b.Dispose();

        b = null;

    } // End finally

} // End m_comboBox_DrawItem()

All I really have to do is keep track of the item index and use that value to locate the proper FontFamily object. From there, it is simply a matter to draw the name of the font to the screen.

Conclusion

To be sure, there is a little more going on inside the control. However, most of it relates to forwarding events and properties to the embedded combobox control. Pretty boring stuff.

This code is new, and relatively untested. If you find bugs, just let me know and I'll do my best to squash them.

Have fun! :o)

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)

About the Author

Martin Cook
Web Developer
United States United States
Member
I am a C# developer specializing in creating object-oriented software for Microsoft Windows. When I am not programming I enjoy reading, playing the guitar/piano, running, watching New York Ranger hockey, designing and building wacky electronic devices, and of course enjoying good times with my wife and children.

Sign Up to vote   Poor Excellent
Add a reason or comment to your vote: x
Votes of 3 or less require a comment

Comments and Discussions

 
You must Sign In to use this message board.
Search this forum  
    Spacing  Noise  Layout  Per page   
GeneralMy vote of 5mvpKanasz Robert27 Sep '12 - 10:53 
good job
QuestionSpeedmemberMember 769646511 Jun '12 - 2:34 
Hi There,
It is really good but when opening a form with it on it is really slow as it loads the fonts is there anyway of speeding this process up and anyone wanting to fix the selectedindex or selectedfontfamily
For selectedfontfamily
Add m_comboBox.Text = value.Name; to public FontFamily SelectedFontFamily
 
Before
// Select the item.
m_comboBox.SelectedIndex = index;
After
// Select the item.
m_comboBox.SelectedIndex = index;
m_comboBox.Text = value.Name;
 
For selectedindexchanged
do same as above
 
// End for all the fonts.
m_comboBox.SelectedIndex = value;
m_comboBox.Text = (string)m_comboBox.Items[value];

GeneralGreat component!memberSonOfGrey3 Mar '10 - 22:30 
Hi there,
 
Just wanted to tell you that I've used your font combobox in a project of mine. If I ever release it to the public, I'll be sure to mention you in the credits!
 
Thanks!
GeneralRe: Great component!memberStefan Strube7 Aug '11 - 8:10 
Yeah, also for me this helped a lot! Thank you for the great work!
 
Just one hint: You should call CreateHandle() in setter of FontFamily, cause otherwise it is not possible to initialize/set the font before the form was created.
---
Das Seltsamste an der Gegenwart mag der Umstand sein, dass man sie dereinst die gute alte Zeit nennen wird!
Stru.be - Software Developer

QuestionDefault font?memberKevin Warner18 Apr '09 - 10:15 
Did anyone figure out how to set the default font? I've put this on a tool strip and it works as advertised. But, I can't get ".SelectedFontFamily=myFont.FontFamily.name" to show anything in the box.
Thanks for any help
KWarner
GeneralProblem in VB .netmemberagriweb23 Apr '08 - 8:25 
I've wrote similar code in vb .net, it works fine except after selecting a fonttype(in this case Arial Black) the combobox text is something like this "Arial Black; 8pt; style=Bold" . With other words, the textfield of the combobox shows the name of the font object not the name of the font only. Working with the events 'textupdate' and 'textchanged' brings no solution. I hope someone can help.
GeneralRe: Problem in VB .netmemberMartin Cook24 Apr '08 - 2:27 
That's because the combobox contains references to FontFamily objects in it's 'Items' collection. The 'ToString' method on the FontFamily class produces a string just as you describe: 'Arial Black; 8pt; style=...' The combobox uses that string by default. That's why this control processes the 'DrawItem' event, so that it can draw the font using the name of the font rather than the default representation of the FontFamily object. That's also why this control contains the 'SelectedFontFamily' property, so that users of the control can have all the information about the selected font - not just the name.
 
That's not to say mine is the only way to do things though. It's just the way I came up with. I'm always open to suggestions...
 
If the FontFamily class wasn't sealed you might be able to override the 'ToString' method so that it would produce the font name instead of all the other font info. Then you could just substitute your custom FontFamily class in place of the standard one. Since that wont work I guess you could try overriding the 'OnTextUpdate' or 'OnTextChanged' methods in the combobox and see if it's possible to modify the event arguments before the events themselves fire. I'm not sure if that will work or not, but you can research the idea.
 
BTW, I'm sure CP readers would be interested in seeing your implementation of a font combobox. Are you planning an article?
 
It's been ages since I looked at this code. I hope remembered things well enough to have answered your questions.
 
Martin Cook
Jesus answered, "I am the way and the truth and the life. No one comes to the Father except through me." John 14:6

QuestionFont ToolStripComboBox?memberTim8w18 Apr '08 - 11:40 
How can I modify this code so that it will work for a ToolStripComboBox? ToolStripComboBox does not have a 'SelectedIndexChanged' event, only a 'Paint' event. Any help would be appreciated...
 
Tim Alvord

GeneralRe: Font ToolStripComboBox?memberMartin Cook24 Apr '08 - 2:39 
Tim8w, when I look at the ToolStripComboBox class using Visual Studio 2005 I see a 'SelectedIndexChanged' event... maybe you are using an earlier version of .NET?
 
I'm not really sure what your requirements are, but I imagine you could derive from ToolStripComboBox and add the code required to produce the collection of FontFamily objects, then bind the combobox to that collection. It wouldn't really be very different from what's already shown.
 
I hope that helps.
 
Martin Cook
Jesus answered, "I am the way and the truth and the life. No one comes to the Father except through me." John 14:6

GeneralRe: Font ToolStripComboBox? [modified]memberhdr2625 Nov '08 - 5:44 
Tim8W : it's almost the same thing since ToolStripComboBox has a "ComboBox" property that is a Windows.Forms.ComboBox Big Grin | :-D .
A good example here
 
modified on Wednesday, November 26, 2008 12:28 AM

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Rant Rant    Admin Admin   

Permalink | Advertise | Privacy | Mobile
Web02 | 2.6.130523.1 | Last Updated 4 Mar 2005
Article Copyright 2005 by Martin Cook
Everything else Copyright © CodeProject, 1999-2013
Terms of Use
Layout: fixed | fluid