www.gusucode.com > 一个VC++下拉字体预览框源码程序 > 一个VC++下拉字体预览框源码程序\code\FntCombo.cpp
#include "stdafx.h" #include "FntCombo.h" #include "resource.h" // Download by http://www.NewXing.com #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif #define FCB_IMAGEWIDTH 15 ///////////////////////////////////////////////////////////////////////////// // CFontComboBox BEGIN_MESSAGE_MAP(CFontComboBox, CComboBox) //{{AFX_MSG_MAP(CFontComboBox) ON_CONTROL_REFLECT(CBN_CLOSEUP, OnCloseup) ON_WM_NCDESTROY() ON_WM_MOUSEMOVE() ON_WM_LBUTTONDOWN() ON_WM_LBUTTONUP() ON_WM_TIMER() ON_WM_PAINT() //}}AFX_MSG_MAP END_MESSAGE_MAP() ///////////////////////////////////////////////////////////////////////////// // CFontComboBox message handlers int CFontComboBox::CompareItem(LPCOMPAREITEMSTRUCT lpCompareItemStruct) { // return -1 = item 1 sorts before item 2 // return 0 = item 1 and item 2 sort the same // return 1 = item 1 sorts after item 2 /* CString str1,str2; GetLBText(lpCompareItemStruct->itemID1,str1); GetLBText(lpCompareItemStruct->itemID2,str2); if ( str1 < str2 ) { return -1; } else if ( str1 == str2 ) { return 0; } else { return 1; } */ return 0; } void CFontComboBox::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) { ASSERT(lpDrawItemStruct->CtlType == ODT_COMBOBOX); // for easy use CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC); ASSERT(pDC); // attaching failed CRect rect(lpDrawItemStruct->rcItem); // draw focus rectangle if (lpDrawItemStruct->itemState & ODS_FOCUS) pDC->DrawFocusRect(rect); // save the context attributes int nIndexDC = pDC->SaveDC(); CBrush brush; // draw the selection state if (lpDrawItemStruct->itemState & ODS_SELECTED) { brush.CreateSolidBrush(::GetSysColor(COLOR_HIGHLIGHT)); pDC->SetTextColor(::GetSysColor(COLOR_HIGHLIGHTTEXT)); } else { brush.CreateSolidBrush(pDC->GetBkColor()); } pDC->SetBkMode(TRANSPARENT); pDC->FillRect(rect, &brush); CString strCurFont; GetLBText(lpDrawItemStruct->itemID,strCurFont); m_imagelist.Draw(pDC, 0, CPoint(rect.left,rect.top),ILD_TRANSPARENT); int nX = rect.left; // x pos for MRU separater lines rect.left += FCB_IMAGEWIDTH + 2; // create font object LOGFONT lf; ::ZeroMemory(&lf,sizeof(lf)); strcpy(lf.lfFaceName,strCurFont); lf.lfCharSet = DEFAULT_CHARSET; CFont font; font.CreateFontIndirect(&lf); // if it is a symbol font, // draw the font's facename using default font FCBDATA * pFCBData = NULL; if ( m_mapFont.Lookup(strCurFont, pFCBData) && pFCBData->lf.lfCharSet == SYMBOL_CHARSET ) { pDC->TextOut(rect.left, rect.top + 3, strCurFont); SIZE size = pDC->GetTextExtent(strCurFont); rect.left += size.cx; } // now draw the text using created font, CFont * pOldFont = pDC->SelectObject(&font); pDC->TextOut(rect.left,rect.top,strCurFont); // and clean up pDC->SelectObject(pOldFont); font.DeleteObject(); // draw font MRU separator, a line like ============== if ( lpDrawItemStruct->itemID == (UINT)m_mapFontMRU.GetCount() - 1 ) { pDC->MoveTo(nX,rect.bottom - 3); pDC->LineTo(rect.right, rect.bottom - 3); pDC->MoveTo(nX, rect.bottom - 1); pDC->LineTo(rect.right, rect.bottom -1); } // restore state of DC pDC->RestoreDC(nIndexDC); } BOOL CFontComboBox::EnumFont() { LOGFONT lf; HDC hDC = ::GetWindowDC(NULL); // DC for entire screen ZeroMemory(&lf,sizeof(lf)); lf.lfCharSet = DEFAULT_CHARSET; if (!EnumFontFamiliesEx( hDC, // handle to device context &lf, // pointer to logical font information (FONTENUMPROC)EnumScreenFontCallbackFn, // pointer to callback function (LPARAM) this, // application-supplied data (DWORD) 0)) return FALSE; ::ReleaseDC(NULL,hDC); return TRUE; } BOOL CALLBACK AFX_EXPORT CFontComboBox::EnumScreenFontCallbackFn(ENUMLOGFONTEX* pelf, NEWTEXTMETRICEX* /*lpntm*/, int FontType, LPVOID pThis) { if (FontType & RASTER_FONTTYPE) { return 1; } LPCTSTR lpszFace = pelf->elfLogFont.lfFaceName; FCBDATA * pFCBData = NULL; if ( ! strchr(lpszFace, '@') && ! ((CFontComboBox*)pThis)->m_mapFont.Lookup(lpszFace, pFCBData)) { pFCBData = new FCBDATA; pFCBData->flag = 0; pFCBData->lf = pelf->elfLogFont; ((CFontComboBox*)pThis)->m_mapFont.SetAt(lpszFace, pFCBData); } return 1; // call me back next time } void CFontComboBox::Initialize(int nMRUCount /* =10 */) { FCBDATA * pFCBData = NULL; CString strKey,strComp; // enumerate all fonts in system, excluding raster fonts EnumFont(); ResetContent(); int cxMax = 0; CDC* pDC = GetDC(); CFont font; POSITION pos = m_mapFont.GetStartPosition(); while (pos) { m_mapFont.GetNextAssoc(pos,strKey, pFCBData); // calculate width to set if ( pFCBData->lf.lfCharSet == SYMBOL_CHARSET) { pFCBData->lf.lfHeight = 0; pFCBData->lf.lfWidth = 0; font.CreateFontIndirect(&pFCBData->lf); CFont * pOldFont = pDC->SelectObject(&font); SIZE size = pDC->GetTextExtent(pFCBData->lf.lfFaceName, strlen(pFCBData->lf.lfFaceName)); pDC->SelectObject(pOldFont); font.DeleteObject(); SIZE size2 = pDC->GetTextExtent(pFCBData->lf.lfFaceName, strlen(pFCBData->lf.lfFaceName)); if ( cxMax < size.cx + size2.cx) { cxMax = size.cx + size2.cx; } } else { SIZE size = pDC->GetTextExtent(pFCBData->lf.lfFaceName, strlen(pFCBData->lf.lfFaceName)); cxMax = size.cx > cxMax ? size.cx : cxMax; } AddString(strKey); } // set dropped down width to show all the characters SetDroppedWidth(cxMax); m_nMRUCount = nMRUCount; m_imagelist.Create(IDB_FONTTYPE,15,1,RGB(255,0,255)); } void CFontComboBox::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) { lpMeasureItemStruct->itemHeight = 20; } void CFontComboBox::OnCloseup() { int nSel = GetCurSel(); if (nSel != CB_ERR) { CString strFont; GetLBText(nSel,strFont); SetFontMRU(strFont); } } void CFontComboBox::OnNcDestroy() { CComboBox::OnNcDestroy(); m_imagelist.DeleteImageList(); // clean up work to do, // avoiding memory leaks FCBDATA * pFCBData; CString strKey; POSITION pos = m_mapFont.GetStartPosition(); while (pos) { m_mapFont.GetNextAssoc(pos,strKey, pFCBData); delete pFCBData; } } void CFontComboBox::PreSubclassWindow() { CComboBox::PreSubclassWindow(); UINT style = GetWindowLong(m_hWnd, GWL_STYLE); style |= CBS_SORT|CBS_OWNERDRAWVARIABLE; SetWindowLong(m_hWnd, GWL_STYLE, style); // SetWindowPos(NULL,0,0,0,0,SWP_NOSIZE|SWP_NOMOVE|SWP_NOZORDER); // ModifyStyle(0, CBS_SORT|CBS_OWNERDRAWVARIABLE); } void CFontComboBox::SetFontMRU(const CString& strFont) { FCBDATA * pFCBData = NULL; CString strFontDesc; // try to find the font, if not, exit function if ( m_mapFont.Lookup(strFont, pFCBData) ) { if ( m_mapFontMRU.Lookup(strFont, pFCBData) ) { int nSel = FindStringExact(-1, strFont ); ASSERT(nSel != CB_ERR); if ( nSel != 0 ) { DeleteString(nSel); int index = InsertString(0, strFont); ASSERT( index != CB_ERR ); SetCurSel(index); } } else // not in MRU(s) { int nSel = FindStringExact(-1, strFont); if ( m_mapFontMRU.GetCount () >= m_nMRUCount ) { CString str; GetLBText(m_nMRUCount - 1, str); DeleteString(m_nMRUCount - 1); m_mapFontMRU.RemoveKey(str); } if ( nSel != CB_ERR ) { int index = InsertString(0, strFont); ASSERT(index != CB_ERR); SetCurSel(index); pFCBData->flag |= FCB_INMRU; m_mapFontMRU.SetAt(strFont,pFCBData); } } } // lookup in all fonts } /***************************************************************************\ * * NOTE that the following funcitons is for the purpose of flat-drawing * it could be removed if the flat effect is not desired * \***************************************************************************/ void CFontComboBox::DrawCombo(DWORD dwStyle, COLORREF clrTopLeft, COLORREF clrBottomRight) { CRect rcItem; GetClientRect(&rcItem); CDC* pDC = GetDC(); // Cover up dark 3D shadow. pDC->Draw3dRect(rcItem, clrTopLeft, clrBottomRight); rcItem.DeflateRect(1,1); if (!IsWindowEnabled()) { pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNHIGHLIGHT)); } else { pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE), ::GetSysColor(COLOR_BTNFACE)); } // Cover up dark 3D shadow on drop arrow. rcItem.DeflateRect(1,1); rcItem.left = rcItem.right-Offset(); pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE), ::GetSysColor(COLOR_BTNFACE)); // Cover up normal 3D shadow on drop arrow. rcItem.DeflateRect(1,1); pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNFACE), ::GetSysColor(COLOR_BTNFACE)); if (!IsWindowEnabled()) { return; } switch (dwStyle) { case FCB_DRAWNORMAL: rcItem.top -= 1; rcItem.bottom += 1; pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNHIGHLIGHT)); rcItem.left -= 1; pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNHIGHLIGHT)); break; case FCB_DRAWRAISED: rcItem.top -= 1; rcItem.bottom += 1; pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNHIGHLIGHT), ::GetSysColor(COLOR_BTNSHADOW)); break; case FCB_DRAWPRESSD: rcItem.top -= 1; rcItem.bottom += 1; rcItem.OffsetRect(1,1); pDC->Draw3dRect(rcItem, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); break; } ReleaseDC(pDC); } void CFontComboBox::OnLButtonDown(UINT nFlags, CPoint point) { m_bLBtnDown = TRUE; CComboBox::OnLButtonDown(nFlags, point); } void CFontComboBox::OnLButtonUp(UINT nFlags, CPoint point) { m_bLBtnDown = FALSE; Invalidate(); CComboBox::OnLButtonUp(nFlags, point); } void CFontComboBox::OnMouseMove(UINT nFlags, CPoint point) { SetTimer(1,10,NULL); CComboBox::OnMouseMove(nFlags, point); } void CFontComboBox::OnPaint() { Default(); DrawCombo(FCB_DRAWNORMAL, ::GetSysColor(COLOR_BTNFACE), ::GetSysColor(COLOR_BTNFACE)); } void CFontComboBox::OnTimer(UINT nIDEvent) { POINT pt; GetCursorPos(&pt); CRect rcItem; GetWindowRect(&rcItem); static bool bPainted = FALSE; // OnLButtonDown, show pressed. if (m_bLBtnDown) { KillTimer (1); if (bPainted) { DrawCombo(FCB_DRAWPRESSD, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); bPainted = FALSE; } return; } // If mouse leaves, show flat. if (!rcItem.PtInRect(pt)) { KillTimer (1); if (bPainted) { DrawCombo(FCB_DRAWNORMAL, ::GetSysColor(COLOR_BTNFACE), ::GetSysColor(COLOR_BTNFACE)); bPainted = FALSE; } return; } // On mouse over, show raised. else { if (bPainted) return; else { bPainted = TRUE; DrawCombo(FCB_DRAWRAISED, ::GetSysColor(COLOR_BTNSHADOW), ::GetSysColor(COLOR_BTNHIGHLIGHT)); } } CComboBox::OnTimer(nIDEvent); }