标题：CFont
CFont
Windows提供了多种与设备无关的不同尺寸的字体。有效地使用这些Windows字体，不用在编程时下很大功夫，就可以明显地增强各种应用程序的功能。字体是Windows GDI必要的组成部分，这意味字体的使用与其他GDI对象一样。它们可以缩放和剪切，可以像选取画笔或者画刷一样选取设备环境。所有关于撤消选中和删除的GDI规则都适用于字体。
字体由CFont类进行管理，创建CFont类必须使用CFont类的成员函数，这点与CPen和CBrush有所不同。
CFont类封装了一个Windows图形设备接口（GDI）字体，并为操作字体提供了成员函数。
为了使用CFont对象，首先构造一个CFont对象，再通过调用CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFontIndirect使一个Windows字体与此CFont对象关联，然后使用此CFont对象的成员函数就可以操作字体了。
一般使用CreatePointFont或CreatePointFontIndirect比使用CreateFont或CreateFontIndirect要更简便，因为前两者会自动的把字体高度的单位由点转换为逻辑单位。
注：“点”是传统计量字大小的单位,是从英文Point来的,一般用小写p表示,俗称“磅”。其换算关系为：1p=0.35146mm≈0.35mm，1英寸=72p。
成员函数
构造函数1、CFont( ); 
构造一个CFont对象。此对象在使用之前应该先使用CreateFont、CreateFontIndirect、CreatePointFont或CreatePointFontIndirect初始化。
初始化函数1、
BOOL CreateFont(
int nHeight,
int nWidth,
int nEscapement,
int nOrientation,
int nWeight,
BYTE bItalic,
BYTE bUnderline,
BYTE cStrikeOut,
BYTE nCharSet,
BYTE nOutPrecision,
BYTE nClipPrecision,
BYTE nQuality,
BYTE nPitchAndFamily,
LPCTSTR lpszFacename 
);
通过指定的一些特征初始化CFont对象。下面分别介绍每个参数：
nHeight：指定字体高度（逻辑单位）。有三种取值：>0，字体映射器将高度值转换为设备单位，并与可用字体的字符元高度进行匹配；=0，字体映射器使用默认的高度值；<0，字体映射器将高度值转换为设备单位，用其绝对值与可用字体的字符高度进行匹配。nHeight转换后的绝对值不应超过16384个设备单位。
nWidth：指定字体中字符的平均宽度（逻辑单位）。
nEscapement：指定偏离垂线和显示界面X轴之间的角度，以十分之一度为单位。偏离垂线是穿过一行文本中第一个字符和最后一个字符的直线。
nOrientation：指定每个字符的基线和设备X轴之间的角度，以十分之一度为单位。
nWeight：指定字体磅数（每1000点中墨点像素数）。可取0到1000之间的任意整数值。
bItalic：指定字体是否为斜体。
bUnderline：指定字体是否带有下划线。
bStrikeOut：指定字体是否带有删除线。
nCharSet：指定字体的字符集。预定义的字符集：
ANSI_CHARSET;BALTIC_CHARSET;CHINESEBIG5_CHARSET;DEFAULT_CHARSET;EASTEUROPE_CHARSET; GB2312_CHARSET; GREEK_CHARSET;HANGUL_CHARSET; MAC_CHARSET; OEM_CHARSET; RUSSIAN_CHARSET; SHIFTJIS_CHARSET;SYMBOL_CHARSET; TURKISH_CHARSET。韩国Windows：JOHAB_CHARSET；中东地区Windows：HEBREW_CHARSSET，ARABIC_CHARSET；泰国Windows：THAI_CHARSET。应用程序可以使用DEFAULT_CHARSET以允许字体名和大小完全指定逻辑字体，如果指定的字体名不存在则可能会用任意字符集的字体来代替，所以为避免不可预料的结果，应谨慎使用DEFAULT_CHARSET。
nOutPrecision：指定输出精度。输出精度定义了输出与要求的字体高度、宽度、字符方向、移位和间距等的接近程度。它的取值及含义如下（只能取其一）：　
OUT_CHARACTER_PRECIS；未用。 　
OUT_DEFAULT_PRECIS：指定缺省的字体映射器状态。 　
OUT_DEVICE_PRECIS：在当系统里有多种字体使用同一个名字时指示字体映射器选择一种设备字体。 　
OUT_OUTLINE_PRCIS：在Windows NT中此值指示字体映射器从TrueType和其他基于边框的字体中选择。 　
OUT_RASTER_PRECIS：在当系统里有多种字体使用同一个名字时指示字体映射器选择一种光栅字体。 　
OUT_STRING_PRECIS：此值没有被字体映射器使用，但是当列举光栅字体时它会被返回。 　
OUT_STROKE_PRECIS：没有被字体映射器使用，但是当列举TrueType字体、其他基于边框的字体和向量字体时它会被返回。　
OUT_TT_ONLY_PRECIS：指示字体映射器仅从TrueType字体中选择，如果系统中没有安装TrueType字体，则字体映射返回缺省状态。　
OUT_TT_PRECIS：在当系统里有多种同名的字体时指示字体映射器选择一种TrueType字体。当操作系统含有多种与指定名字同名的字体时，应用程序可以使用OUT_DEVICE_PRECIS，OUT_RASTER_PRECIS和OUT_TT_PRECIS值来控制字体映射器如何选择一种字体，例如，如果操作系统含有名字Symbol的光栅和TrueType两种字体，指定OUT_TT_PRECIS使字体映射器选择TrueType方式（指定OUT_TT_ONLY_PRECIS强制字体映射器选择一种TrueType字体，尽管这会给TrueType字体换一个名字）。
nClipPrecision：指定裁剪精度。裁剪精度定义了怎样裁剪部分超出裁剪区域的字符。它的取值及含义如下（可取一个或多个值）：
CLIP_DEFAULT_PRECIS：指定缺省裁剪状态。
CLIP_CHARACTER_PRECIS：未用。 　
CLIP_STROKE_PRECIS：未被字体映射器使用，但是当列举光栅字体、向量字体或TrueType字体时它会被返回。在Windows环境下，为保证兼容性，当列举字体时这个值总被返回。 　
CLIP_MASK：未用。
CLIP_EMBEDDED：要使用嵌入式只读字体必须使用此标志。 　
CLIP_LH_ANGLES：当此值被使用时，所有字体的旋转依赖于坐标系统的定位是朝左的还是朝右的。如果未使用此值，设备字体总是逆时针方向旋转，但其他字体的旋转依赖于坐标系统的定向。 　
CLIP_TT_ALWAYS：未用。
nQuality：指定字体的输出质量。输出质量定义了GDI将逻辑字体属性匹配到实际物理字体的细致程度。它的各个取值及含义如下（取其一）：
DEFAULT_QUALITY：字体的外观不重要。 　
DRAFT_QUALITY：字体外观的重要性次于使用PROOF_QUALITY时，对GDI光栅字体，缩放比例是活动的，这意味着多种字体大小可供选择，但质量可能不高，如果有必要，粗体、斜体、下划线、strikeout字体可被综合起来使用。 　
PROOF_QUALITY：字符质量比精确匹配逻辑字体字体属性更重要。对GDI扫描字体，缩放比例是活动的，并选择最接近的大小。尽管当使用PROOF_QUALITY时，选择字体大小并不完全匹配，但字体的质量很高，并没有外观上的变形。如果有必要，粗体、斜体、下划线、strikeout字体可被综合起来使用。 
nPitchAndFamily：指定字体间距和字体族。低2位用来指定字体的间距，可取下列值中的一个：DEFAULT_PITCH，FIXED_PITCH，VARIABLE_PITCH。高4位指定字体族，取值及含义如下（取其一）：
FF_DECORATIVE：新奇的字体，如老式英语（Old English）。
FF_DONTCARE：不关心或不知道。 　
FF_MDERN：笔划宽度固定的字体，有或者无衬线。如Pica、Elite和Courier New。 　
FF_ROMAN：笔划宽度变动的字体，有衬线。如MS Serif。 　
FF_SCRIPT：设计成看上去象手写体的字体。如Script和Cursive。 　
FF_SWISS：笔划宽度变动的字体，无斜线。如MS Sans Serif。 　
应用程序可以用运算符OR将字符间距和字体族组合起来给nPitchAndFamily赋值。 　
字体族描述一种字体的普通外观，当所有的精确字样都不能使用时，可用它们来指定字体。
lpszFacename：指定字体的字样名的字符串。此字符串的长度不应超过30个字符。Windows函数EnumFontFamilies可以枚举出当前所有可用字体的字样名。如果lpszFacename为NULL，则GDI使用一种与设备无关的字体。
返回值：此函数成功则返回TRUE，否则返回FALSE。
CreateFont函数初始化CFont对象后，此字体就能够被选作任何设备上下文的字体了。此函数并不会创建一个新的Windows GDI字体，只是从GDI的物理字体中选择了一个最匹配的字体。在创建一个逻辑字体时，大部分参数可以使用默认值，但一般情况下都会给出参数nHeight和lpszFacename的指定值，如果没有给nHeight和lpszFacename参数设定取值，则创建的逻辑字体与设备相关。当使用CreateFont函数初始化一个CFont对象完成后，就能够使用CDC::SelectObject函数来为设备上下文选择字体了，并且还能够在不再使用此CFont对象时删除它。
2、BOOL CreateFontIndirect(const LOGFONT* lpLogFont);
通过一个LOGFONT结构体变量给出的特征来初始化CFont对象。参数lpLogFont是指向LOGFONT结构体变量的指针，此LOGFONT结构体变定义了逻辑字体的特征。LOGFONT结构体的定义可以参见VS2010/MFC编程入门之十八（对话框：字体对话框）。
3、BOOL CreatePointFont(int nPointSize,LPCTSTR lpszFaceName,CDC* pDC = NULL);
此函数提供了一种由指定字样和点数创建字体的简单方式。参数的意义如下：
nPointSize：指定字体高度，以十分之一点为单位。例如，nPointSize为120则表示是12点的字体。
lpszFacename：指定字体的字样名的字符串。此字符串的长度不应超过30个字符。Windows函数EnumFontFamilies可以枚举出当前所有可用字体的字样名。如果lpszFacename为NULL，则GDI使用一种与设备无关的字体。
pDC：指向CDC对象，用来将nPointSize指定的高度转换为逻辑单位，如果为NULL，则使用屏幕设备上下文进行转换。
4、BOOL CreatePointFontIndirect(const LOGFONT* lpLogFont,CDC* pDC = NULL);
此函数是通过指定的字样和点数创建字体的间接方式。参数lpLogFont指向一个LOGFONT结构体变量，此LOGFONT变量定义了逻辑字体的特征，它的lfHeight成员以十分之一点为单位，而不是逻辑单位。参数pDC指向CDC对象，用来将lfHeight表示的高度转换为逻辑单位，如果为NULL，则使用屏幕设备上下文进行转换。
此函数与CreateFontIndirect很相似，但区别是LOGFONT变量中lfHeight成员的单位是十分之一点而不是逻辑单位。
操作1、static CFont* PASCAL FromHandle(HFONT hFont);
由Windows GDI字体的HFONT句柄获得相应的CFont对象指针。参数hFont是一个Windows字体的HFONT句柄。成功则返回CFont对象的指针，否则返回NULL。
属性1、int GetLogFont(LOGFONT * pLogFont);
获取CFont对象的LOGFONT结构体的拷贝。参数pLogFont指向用来接收字体信息的LOGFONT结构体变量。成功则返回非零值，否则返回零。[1]
用法举例

（一）显示倾斜的文字
上文中的图一显示了通过显示一系列的倾斜字符串来实现环绕显示的效果，下面来详细说明如何实现这个效果。
实现上述的效果其实很容易，只要使用CFONT类和LOGFONT结构来灵活的创建字体，设置字体的属性，就可以实现倾斜文字的效果。LOGFONT结 构中包含了所要创建的字体中的全部信息，其中的ifEscapement 成员制定了所创建的字体与水平方向所倾斜的角度，需要读者注意的是该成员变量角度的单位是十分之一度而不是度，例如，如果ifEscapement定义为 450，它表示字体的倾斜角度为45度。为了保证所有的字体按照一个方向旋转，一定要设置ifEscapenent的CLIP_LH_ANGLES位，否 则字体有可能向反方向旋转。
如同使用其它GDI（图形用户界面接口）对象一样，在使用你定义的字体以前，必须要将创建的字体选入DC中（设备上下文）。
（二）实现3D文字
计算机屏幕是平面二维的，我们之所以能欣赏到真如实物般的三维图像，是因为显示在计算机屏幕上时色彩灰度的不同而使人眼产生视觉上的错觉，而将二维的计 算机屏幕感知为三维图像。基于色彩学的有关知识，三维物体边缘的凸出部分一般显高亮度色，而凹下去的部分由于受光线的遮挡而显暗色。这一认识被广泛应用于 网页或其他应用中对按钮、3D线条的绘制。对于本文所要绘制的3D文字同样也适用，即在原始位置显示高亮度颜色，而在左下或右上等位置用低亮度颜色勾勒出 其轮廓，这样在视觉上便会产生3D文字的效果。具体实现时，可用完全一样的字体在不同的位置分别绘制两个不同颜色的2D文字，只要使两个文字的坐标合适， 就完全可以在视觉上产生出不同效果的3D文字。
具体实现的思想是通过CDC：：SetTextColor（）分别设置文字的颜色为高亮（3DHILIGHT）和阴影（3DSHADOW）的状态下显示文字；同时注意在两次显示文字时要错开几个像素，这样才能达到预期的效果。实现的效果上文的图二所示。
（三）文字的渐变效果
为了实现文字的渐变效果，需要设置一个定时器（使用SetTimer（）函数），在定时器响应函数处理过程中，通过调用CDC： SetTextColor()函数不断改变设备上下文中文本的显示颜色，从而实现文字的渐变效果。文本的颜色是通过RGB（红、绿、兰）三种基本颜色的混 合所形成的最终结果，RGB三基色的变化范围都是（0，255），R=G=B时，颜色的效果是灰色的，所谓灰色，就是在纯白和纯黑之间的一种过渡色，当R =G=B=0时，颜色为黑色，当R=G=B=255时，颜色为纯白色，可以定义一个修正变量，不断的对该三基色进行递增或递减，从而实现文字的渐变显示。 这里仅仅给出实现的思路，读者自己可以很容易的实现代码。
（四）其它
另外，还可以通过设置路径对象来对普通的文字进行轮廓勾勒，使之具备特殊的效果。路径是Win32中新增的一个GDI对象，下面先从概念上谈起。
1）路径的概念
在Windows 95/NT 这样的Win32操作系统中，除了已有的位图，画笔，画刷，字体，调色板和区域之外，还增加了一个新的GDI对象：路径。路径是可以被填充，画出轮廓或同 时被画出轮廓并填充的一个或多个图形。路径的引入，大大地丰富了Windows的图形功能，使得应用程序可以方便地建立复杂区域，绘制和填充不规则图形。 这里说的不规则图形是指由直线和贝塞尔曲线组成的图形（相对于矩形，多边形，椭圆等规则图形）。
2）路径的使用
与其它原有的GDI对象不同的是，MFC类库没有专门用一个C++类来封装路径对象（或许在以后的版本中会得到支持）。有关路径的定义和使用等各种操作都必须通过调用API函数（或CDC类中对应的成员函数）来实现。路径的使用过程大致如下：
（1）调用BeginPath()函数开始路径定义；
（2）调用GDI绘图函数来定义路径；在Win32中，可以用于定义路径的GDI绘图函数包括：AngleArc（）、 Arc（）、 ArcToChord（）、Ellipse （）、LineTo（）、TextOut（）等函数；
（3）调用EndPath()函数结束路径定义；　
完成路径定义后，所定义的路径即被同时选进设备描述表，设备描述表中原有的路径对象在调用BeginPath()函数开始路径定义时即被废弃。
（4）使用路径对象。
完成路径定义工作之后，应用程序便可以利用有关GDI函数来使用路径，这些函数包括绘制路径轮廓StrokePath()，填充路径FillPath ()，绘制轮廓并填充StrokeAndFillPath()，把路径转换成区域PathToRegion()，把路径直线化FlattenPath ()，提取路径数据GetPath()，加宽路径WidenPath()和设置裁剪路径SelectClipPath()等。这些函数的具体使用方法可参 阅有关的SDK文档。
下面的代码演示了如何实现字体的空心效果
////////////////////////////////////// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄 
CPaintDC dc(this); // 更改当前字体 
LOGFONT lf; 
dc.GetCurrentFont()- >GetLogFont(&lf);
CFont font; 
CFont *pOldFont; // 保存设备上下文最初使用的字体对象 
lf.lfCharSet=134; 
lf.lfHeight=-150; 
lf.lfHeight=-150; 
lf.lfWidth=0; 
strcpy(lf.lfFaceName, "隶书");
font.CreateFontIndirect( &lf);
pOldFont=dc.SelectObject( &font);
dc.SetBkMode(TRANSPARENT); // 更改当前画笔 
CPen pen(PS_SOLID, 1, RGB(255, 0, 0)); 
CPen *pOldPen; 
pOldPen=dc.SelectObject( &pen); // 开始一个路径 
dc.BeginPath(); 
dc.TextOut(10, 10, "空心字");
dc.EndPath(); // 绘制路径 
dc.StrokePath(); 
//可以用dc.StrokeAndFillPath()函数来代替，不过该函数会使用当前刷子填充路径的内部。 
dc.SelectObject(pOldFont); 
dc.SelectObject(pOldPen); 
}