您的位置:首页 > 编程语言 > C语言/C++

VC++界面编程之--动态安装字体(CFont)

2013-08-27 21:08 197 查看


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
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: