Owner Drawn Font Selection Combobox

Following is a owner drawn Combo Box which will be filled with the names of the fonts.. And each entry is in same font as selected. This is something similar to the one in Netscape 4.x font selector.

This is pretty simple. All it does is to enumerate the fonts and store the LOGFONTs in the Item data. and when the painting is to be done, takes the value from the Item data and paints the item..

It has a very nice effect.. Since this does only the font names, you might need another combobox for the sizes..

You can also set the colors for the highlight and normal..

To use this, Create a ComboBox in your Resource Editor, Set the Owner draw to "Variable" and check the "Has strings".

Then, In the OnInitDialog () or OnInitialUpdate() call the function FillFonts (). Thats it.. You have got your fonts in the Combo box. To get the selected font, Use GetSelFont () with LOGFONT& as the argument. this argument will be filled in upon return.

P.S:If you make the ComboBox to be a "Drop down List" then the edit window (actually the static control window) will hav the name in the same font as selected.. Otherwise, it will be in the dialog box's font..


#if !defined(AFX_CUSTCOMBOBOX_H__F8528B4F_396E_11D1_9384_00A0248F6145__INCLUDED_)
#define AFX_CUSTCOMBOBOX_H__F8528B4F_396E_11D1_9384_00A0248F6145__INCLUDED_

#if _MSC_VER >= 1000
#pragma once
#endif // _MSC_VER >= 1000
// CustComboBox.h : header file

// CCustComboBox window

typedef enum {FONTS} STYLE;      //Why have I enumerated, Cos, Maybe I might want something other than Fonts here

class CCustComboBox : public CComboBox
// Construction
     CCustComboBox (STYLE);

// Attributes
     void SetHilightColors (COLORREF hilight,COLORREF hilightText)
          m_clrHilight = hilight;
          m_clrHilightText = hilightText;
     void SetNormalColors (COLORREF clrBkgnd,COLORREF clrText)
          m_clrNormalText = clrText;
          m_clrBkgnd = clrBkgnd;
     static BOOL CALLBACK EnumFontProc (LPLOGFONT lplf, LPTEXTMETRIC lptm, DWORD dwType, LPARAM lpData);
     void FillFonts ();
     int  GetSelFont (LOGFONT&);

// Operations

// Overrides
     // ClassWizard generated virtual function overrides
     virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
     virtual void MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct);
     virtual void PreSubclassWindow();

// Implementation
     virtual ~CCustComboBox();

     // Generated message map functions
     STYLE m_enStyle;
     COLORREF m_clrHilight;
     COLORREF m_clrNormalText;
     COLORREF m_clrHilightText;
     COLORREF m_clrBkgnd;
     BOOL m_bInitOver;

     void DrawDefault (LPDRAWITEMSTRUCT);
     void DrawFont(LPDRAWITEMSTRUCT);

     void InitFonts ();
     afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
     afx_msg void OnDestroy();
     afx_msg   long OnInitFonts (WPARAM, LPARAM);


// Microsoft Developer Studio will insert additional declarations immediately before the previous line.

#endif //!defined(AFX_CUSTCOMBOBOX_H__F8528B4F_396E_11D1_9384_00A0248F6145__INCLUDED_)

// CustComboBox.cpp : implementation file

#include "stdafx.h"
#include "CustComboBox.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;

#define WM_INITFONTS          (WM_USER + 123)
//I chose 123 cos nobody might use the same exact number.. I can improve this by use RegisterWindowMessage..

// CCustComboBox

//Initial values of the text and highlight stuff

     m_enStyle = FONTS;
     m_clrHilight = GetSysColor (COLOR_HIGHLIGHT);
     m_clrNormalText = GetSysColor (COLOR_WINDOWTEXT);
     m_clrHilightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
     m_clrBkgnd = GetSysColor (COLOR_WINDOW);
     m_bInitOver = FALSE;


CCustComboBox::CCustComboBox (STYLE enStyle)
     m_enStyle = enStyle;
     m_clrHilight = GetSysColor (COLOR_HIGHLIGHT);
     m_clrNormalText = GetSysColor (COLOR_WINDOWTEXT);
     m_clrHilightText = GetSysColor (COLOR_HIGHLIGHTTEXT);
     m_clrBkgnd = GetSysColor (COLOR_WINDOW);
     m_bInitOver =FALSE;



// CCustComboBox message handlers

void CCustComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
     //I might want to add something else someday
     switch (m_enStyle)
     case FONTS:

//I dont need the MeasureItem to do anything. Whatever the system says, it stays

void CCustComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct)

void CCustComboBox::DrawFont(LPDRAWITEMSTRUCT lpDIS)
     CDC* pDC = CDC::FromHandle(lpDIS->hDC);
     CRect rect;

     TRACE0 ("In Draw Font\n");

    // draw the colored rectangle portion

     pDC->SetBkMode( TRANSPARENT );

     if (lpDIS->itemState & ODS_SELECTED)
          pDC->FillSolidRect (rect,m_clrHilight);
          pDC->SetTextColor (m_clrHilightText);
          pDC->FillSolidRect (rect,m_clrBkgnd);
          pDC->SetTextColor (m_clrNormalText);

     if ((int)(lpDIS->itemID) < 0) // Well its negetive so no need to draw text
          CString strText;
          GetLBText (lpDIS->itemID,strText);
          CFont newFont;
          CFont *pOldFont;

          ((LOGFONT*)lpDIS->itemData)->lfHeight = 90; //9 point size
          ((LOGFONT*)lpDIS->itemData)->lfWidth = 0;
          newFont.CreatePointFontIndirect ((LOGFONT*)lpDIS->itemData);
          pOldFont = pDC->SelectObject (&newFont);
          pDC->DrawText(strText, rect, DT_LEFT | DT_VCENTER | DT_SINGLELINE);
          pDC->SelectObject (pOldFont);
          newFont.DeleteObject ();

void CCustComboBox::InitFonts ()
     CDC *pDC = GetDC ();
     ResetContent (); //Delete whatever is there
     EnumFonts (pDC->GetSafeHdc(),NULL,(FONTENUMPROC) EnumFontProc,(LPARAM)this);//Enumerate
     m_bInitOver = TRUE;

BOOL CALLBACK CCustComboBox::EnumFontProc (LPLOGFONT lplf, LPTEXTMETRIC lptm, DWORD dwType, LPARAM lpData)
     if (dwType == TRUETYPE_FONTTYPE) //Add only TTF fellows, If you want you can change it to check for others
          int index = ((CCustComboBox *) lpData)->AddString(lplf->lfFaceName);
          LPLOGFONT lpLF;
          lpLF = new LOGFONT;
          CopyMemory ((PVOID) lpLF,(CONST VOID *) lplf,sizeof (LOGFONT));
          ((CCustComboBox *) lpData)->SetItemData (index,(DWORD) lpLF);
     return TRUE;

int CCustComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
     if (CComboBox::OnCreate(lpCreateStruct) == -1)
          return -1;

     // TODO: Add your specialized creation code here
     if (m_enStyle == FONTS)
          PostMessage (WM_INITFONTS,0,0);
     return 0;

long CCustComboBox::OnInitFonts (WPARAM, LPARAM)
     InitFonts ();
     return 0L;

void CCustComboBox::OnDestroy()

     if (m_enStyle == FONTS)
          int nCount;
          nCount = GetCount ();
          for (int i = 0; i <  nCount; i++)
               delete ((LOGFONT*)GetItemData (i)); //delete the LOGFONTS actually created..
     // TODO: Add your message handler code here

void CCustComboBox::FillFonts ()
     m_enStyle = FONTS;
     PostMessage (WM_INITFONTS,0,0); //Process in one place

int  CCustComboBox::GetSelFont (LOGFONT& lf)
     int index = GetCurSel ();
     if (index == LB_ERR)
          return LB_ERR;
     LPLOGFONT lpLF = (LPLOGFONT) GetItemData (index);
     CopyMemory ((PVOID)&lf, (CONST VOID *) lpLF, sizeof (LOGFONT));
     return index; //return the index here.. Maybe the user needs it:-)

void CCustComboBox::PreSubclassWindow()
     // TODO: Add your specialized code here and/or call the base class
     //Tried to do what Roger Onslow did for the button.. Did not work..?? Any R&D guys around :-)


  • good`

    Posted by xixihaha on 12/02/2010 05:50am

    so nice ,hahah

  • How Can I do Dynamic Creation of a ComboBox

    Posted by subbaraovnrt on 12/15/2004 07:59am

    In a Dialog box I used one Push Button When I press that button New Combobox Dynamically created but the all font in that ComboBox all are same bold Arial.
    How my Dialog box behaves as static your implementation.

  • How to initalize the Font combobox after FillFonts()

    Posted by Legacy on 11/14/2001 12:00am

    Originally posted by: Chris Hambleton

    To initalize the Font combobox after FillFonts(), simply change the PostMessage() calls to SendMessage().

    PostMessage() returns as soon as the message is posted (while the combobox is still empty), but SendMessage() returns only after the message has been handled (after the combobox has been filled).

    The reason you're currently unable to initialize the Font combobox is because you're calling SetCurSel() / SetString() on a combobox that's currently empty.

    Hope this helps!!

  • How do you intialize the editor box?

    Posted by Legacy on 11/05/2001 12:00am

    Originally posted by: Butch


    But how do you initialize the editor box portion of the combo to say a default font selection?


  • !!!

    Posted by Legacy on 07/11/2001 12:00am

    Originally posted by: Chethana Sastry

    This is great. I could finish a week's work in just 15 mins!

    I have a problem though...
    If i say SetCurSel(0) it fails and returns -1
    Have you encountered the same problem? If so, what is the solution?

  • super

    Posted by Legacy on 02/08/2001 12:00am

    Originally posted by: pierre


    its works

  • Great !

    Posted by Legacy on 05/01/2000 12:00am

    Originally posted by: Ergin Salih

    This is wonderful, it is easily modified to work off a list
    of font objects.

    Exactly what I wanted.


Leave a Comment
  • Your email address will not be published. All fields are required.

Top White Papers and Webcasts

  • Moving from an on-premises environment to Office 365 does not remove the need to plan for disruptions or reduce the business risk requirements for protecting email services. If anything, some risks increase with a move to the cloud. Read how to ease the transition every business faces if considering or already migrating to cloud email. This white paper discusses: Setting expectations when migrating to Office 365 Understanding the implications of relying solely on Exchange Online security Necessary archiving …

  • Complex hybrid environments can make it difficult to track interdependencies, increasing the risk of disrupting critical business services. In this white paper by EMA, you'll learn how application discovery and dependency mapping can help you: Meet granular targets for availability, cost, and time-to-revenue for cloud services. Accelerate mean time to repair (MTTR) while communicating better with stakeholders. Manage even the most complex hybrid environments more efficiently and effectively Understand the …

Most Popular Programming Stories

More for Developers

RSS Feeds

Thanks for your registration, follow us on our social networks to keep up-to-date