1. 起因:
在界面编程时,我们经常需要用到自定义字体,来使自己的界面更美观。可要是别人电脑上没有你预定义的字体就麻烦了,你的界面字体会被Windows默认字体所取代,然后控件变形、错位等等问题会接踵而至。
2. 解决办法:
遇到这种情况,我们可以把字体放在Visual Studio的自定义资源中,和exe一起打包。还有一种办法是将字体打包在dll中或者放在一个文件夹中,这样可以减少exe的体积。这里为了方便讲解,我将字体放入至自定义资源中,用一个ID值来索引它即可。
首先,将字体加入至resource文件中,因为我的字体文件是ttf格式的,所以给他取名为TTF,如下图:
我这里使用了2个字体,一个是中文篆体,一个是英文android字体。
接下来,我们需要用到Windows的两个API函数,来让Windows安装字体,或者是卸载字体。当你的程序完全退出时,可以将字体卸载。这两个函数分别是:AddFontMemResourceEx和RemoveFontMemResourceEx,他们是为GDI设计的,而GDI+可以直接使用PrivateFontCollection下的AddMemoryFont函数来进行字体的加载即可。
我这里设计了个类,它可以用在GDI和GDI+上面,可能有的看官会觉得多此一举,直接GDI+不就好了么?为什么还要照顾GDI呢?那是因为,我们的控件的设置字体SetFont还是基于GDI的,GDI+中的字体没办法直接用在上面。
GDI+中的字体要想转换为GDI的HFONT,就得用CreateFontIndirect来转换。转换得到的字体,在不用时,需要用DeleteObject删除之。以下是这个类的完整代码:
class CFontHelper
{
// Constructor, destructor and operator.
public:
CFontHelper() : m_Font(NULL), m_hFontRes(NULL), m_pData(NULL), m_nSize(0)
{
}
~CFontHelper()
{
DeleteOldFont();
}
// Data members.
public:
Font* m_Font;
private:
PrivateFontCollection m_FontCollection;
FontFamily m_FontFamily;
HANDLE m_hFontRes;
void* m_pData;
int m_nSize;
// Operations.
public:
void DeleteOldFont()
{
if (m_Font != NULL)
{
delete m_Font;
m_Font = NULL;
}
if (m_hFontRes != NULL)
{
RemoveFontMemResourceEx(m_hFontRes);
m_hFontRes = NULL;
}
}
// Load font from resource manager.
BOOL LoadFont(ATL::_U_STRINGorID resource, ATL::_U_STRINGorID type = _T("ttf"))
{
CResource res;
if( !res.Load(type, resource) )
{
ATLASSERT(FALSE);
return FALSE;
}
m_nSize = (int)res.GetSize();
m_pData = res.Lock();
Gdiplus::Status nResults = m_FontCollection.AddMemoryFont(m_pData, m_nSize);
if( nResults != Gdiplus::Ok )
{
ATLASSERT(FALSE);
return FALSE;
}
DWORD dwNum = 1;
SetFontStyle();
return TRUE;
}
// Modify font style.
BOOL SetFontStyle(Gdiplus::FontStyle fontstyle = FontStyleRegular, REAL nFontSize = 14.0F)
{
int nNumFound = 0;
m_FontCollection.GetFamilies(1, &m_FontFamily, &nNumFound);
DWORD dwFound = (DWORD)nNumFound;
if (nNumFound <= 0)
{
// You need load font first.
ATLASSERT(FALSE);
return FALSE;
}
// Delete old font.
DeleteOldFont();
m_Font = new Font(&m_FontFamily, nFontSize, fontstyle, UnitPixel);
m_hFontRes = AddFontMemResourceEx(m_pData, (DWORD)m_nSize, NULL, &dwFound);
if (m_Font != NULL)
{
return TRUE;
}
ATLASSERT(FALSE);
return FALSE;
}
// Turn GDI+ Font to HFONT (ANSI).
HFONT FontToHFONT_A(HWND m_hWnd)
{
if (m_Font == NULL || m_hWnd == NULL)
{
ATLASSERT(FALSE);
return NULL;
}
Graphics g(m_hWnd);
LOGFONTA logFont;
m_Font->GetLogFontA(&g, &logFont);
logFont.lfQuality = CLEARTYPE_QUALITY;
logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
logFont.lfClipPrecision = CLIP_CHARACTER_PRECIS;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
return ::CreateFontIndirectA(&logFont);
}
// Turn GDI+ Font to HFONT (UNICODE).
HFONT FontToHFONT_W(HWND m_hWnd)
{
if (m_Font == NULL || m_hWnd == NULL)
{
ATLASSERT(FALSE);
return NULL;
}
Graphics g(m_hWnd);
LOGFONTW logFont;
m_Font->GetLogFontW(&g, &logFont);
logFont.lfQuality = CLEARTYPE_QUALITY;
logFont.lfOutPrecision = OUT_TT_ONLY_PRECIS;
logFont.lfClipPrecision = CLIP_CHARACTER_PRECIS;
logFont.lfCharSet = DEFAULT_CHARSET;
logFont.lfPitchAndFamily = DEFAULT_PITCH;
return ::CreateFontIndirectW(&logFont);
}
};
好了,让我们新建个窗口,并创建两个CEdit控件,并用SetFont来设置他们的字体,看看是不是很简单?说真的,我们老祖宗创建的篆体是不是很好看呢?看来编程之余还得多多学习国学方面的知识啊,编程之美,国学之美,嘿嘿。
本文代码工程免费下载链接:http://download.csdn.net/detail/renstarone/6022471