在 Duilib 中,我们可以定义多种字体,不同的控件使用不同的字体来丰富我们的界面,今天我们来介绍一下 Duilib 是如何使用字体的。
首先,Duilib 中定义字体的方法如下:
<Font id="0" name="Microsoft YaHei" size="12" bold="false" italic="false" default="true"/>
<Font id="1" name="Microsoft YaHei" size="14" bold="false" italic="false"/>
<Font id="2" name="Microsoft YaHei" size="16" bold="false" italic="false"/>
<Font id="3" name="Microsoft YaHei" size="18" bold="false" italic="false"/>
在之前的 xml 解析篇中,我们已经知道, xml 解析是按节点进行解析的。 <Font>
类型的节点也有对应的 CMarkupNode
对象被保存起来,解析完成后,根据 CMarkupNode
创建控件等内容时,当遇到 <Font>
节点,则解析出对应的属性,将创建的字体保存在 CPaintManagerUI
中。
接下来看一下字体保存的数据结构是什么样的,字体信息被保存在一个 Map 中,类型为 : CDuiStringPtrMap
。 Key 是字体的 id, Value 是 TFontInfo*
类型的字体信息,当需要取得某控件的字体属性时,则调用 TFontInfo* CPaintManagerUI::GetFontInfo(int id)
获取到对应的字体信息来绘制文字。 那么 TFontInfo*
类型对象又是如何创建的呢?接下来我们来看一下 CPaintManagerUI::AddFont
中的关键代码:
LOGFONT lf = { 0 };
::GetObject(::GetStockObject(DEFAULT_GUI_FONT), sizeof(LOGFONT), &lf);
_tcsncpy(lf.lfFaceName, pStrFontName, LF_FACESIZE);
lf.lfCharSet = DEFAULT_CHARSET;
lf.lfHeight = -nSize;
if( bBold ) lf.lfWeight += FW_BOLD;
if( bUnderline ) lf.lfUnderline = TRUE;
if( bItalic ) lf.lfItalic = TRUE;
HFONT hFont = ::CreateFontIndirect(&lf);
if( hFont == NULL ) return NULL;
TFontInfo* pFontInfo = new TFontInfo;
if( !pFontInfo ) return false;
::ZeroMemory(pFontInfo, sizeof(TFontInfo));
pFontInfo->hFont = hFont;
pFontInfo->sFontName = pStrFontName;
pFontInfo->iSize = nSize;
pFontInfo->bBold = bBold;
pFontInfo->bUnderline = bUnderline;
pFontInfo->bItalic = bItalic;
if( m_hDcPaint ) {
HFONT hOldFont = (HFONT) ::SelectObject(m_hDcPaint, hFont);
::GetTextMetrics(m_hDcPaint, &pFontInfo->tm);
::SelectObject(m_hDcPaint, hOldFont);
}
在Windows内部,字体是以一个名为 LOGFONT 的结构来表示(参见:LOGFONT)。第二行中的代码获取了界面默认的 LOGFONT 信息,然后根据函数的传入参数改变对应的属性值,得到新的 LOGFONT 信息后,调用 CreateFontIndirect
获取到 HFONT
,这个就是我们绘制文字时需要用到的字体句柄。 下一段代码就是创建 TFontInfo
类型对象,代码很简单,这里只说一下 ::GetTextMetrics(m_hDcPaint, &pFontInfo->tm)
这行代码,根据指定的 HFONT
,获取对应的 TEXTMETRIC
信息。
这个 TEXTMETRIC
其实是非常有意思的(参见:TEXTMETRIC),如图所示(图片来自百度百科)
这里着重说明几点,具体请参考上面的 LOGFONT 链接:
- tmHeight : 代表字符的高度,不包括行间距 (Duilib 代码中多次用到了这个属性)
- tmInternalLeading :一般用来表示重音符号等
- tmExternalLeading : 图片中没有描绘出来,位于 tmInternalLeading 之上,代表外间距,就是行间距