友情提示:如果本网页打开太慢或显示不完整,请尝试鼠标右键“刷新”本网页!
C语言实例教程(PDF格式)-第48部分
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部! 如果本书没有阅读完,想下次继续接着阅读,可使用上方 "收藏到我的浏览器" 功能 和 "加入书签" 功能!
l lfFaceName=〃宋体〃;
此外,如果为lfFaceName设置了新值,同时也应该将
lfCharSet的值设置为相匹配的字符集。如果字符集与字体名
不相匹配,将会导致设置不起作用。
要使文本向下倾斜输出,我们只需简单的将lfEscapement设置为负
值。如下面的代码所示:
// 将字体输出方向更改为向下倾斜 40 度
lf。lfEscapement=…400;
dc。SelectObject(pOldFont);
font2。DeleteObject();
font2。CreateFontIndirect(&lf);
dc。SelectObject(&font2);
// 计算字符串合适的输出位置
dc。TextOut(290…int(sz。cx*cos(DegToRnd(40))); 10; 〃lfEscapement=…400〃);
上面的代码摘自应用程序FontDemo 。
l 注意:
l 在调用font2的CreateFontIndirect成员函数创建新的字体对象之
前,应该先调用其成员函数DeleteObject删除该字体对象,而当
一个GDI图形对象正为设备上下文所使用时,我们不能删除该图形
对象,因此在前面的代码 中,我们在删除在font2原有的字体对象
之前先将设备上下文的字体对象进行复原。
接着在消息处理函数CMyWnd::OnPaint中,我们又将lfEscapement成
员的值设置为0,输出字符串〃lfEscapement=0〃以示对比。
在随后的代码中,我们演示了lfWeight成员的不同值对字体的笔划粗
细的影响。我们先将lfWeight值设置为0,以50象素的宋体字绘制了
一个 “细”字,然后再将lfWeight值设置为1000,以同样大小和同种
字体绘制了一个 “粗”字。通过如图9。7的输出结果,我们看到字体
笔划的粗细发生的明显的变化。
…………………………………………………………Page 562……………………………………………………………
在OnPaint函数返回之前,不要忘记恢复设备上下文的原有字体对
象,指向该对象的CFont指针在前面被保存到了名为pOldFont的指针
变量中。我们仍然使用SelectObject将其选入当前设备上下文。
上面我们来看示例程序FontDemo的另一个主要的功能板块,即枚举当
前系统中所安装的所有字符并将它添加到一个列表框中。
首先我们在窗口CMyWnd的WM_CREATE消息的处理函数OnCreate中调用
CListBox对象lst (该对象被定义为类CMyWnd的成员变量)的Create成
员函数。在Create成员函数中,我们指定了列表框的样式包括了
LBS_USETABSTOPS,该样式允许在列表项中使用制表符,这些制表符
在显示时会被扩展到指定的位置。
接着,我们将列表框所使用的字体设置为9磅大小的宋体字。这里我
们调用的是CFont对象的CreatePointFont成员函数来创建字体。当需
要创建的指定磅值大小的某种字体时,使用CreatePointFont成员函
数要方便得多,因此该函数仅需要三个参数,并且,第三个参数在很
多情况下可以省略。这样,我们就可以避开填写复杂的LOGFONT结
构。
在改变列表框字体的同时,我们将列表框中的当前制表位设置为200
个对话框单位,对话框单位是一种在控件和对话框使用的度量单位。
每4个水平对话框单位等于以系统字体显示的字符的平均宽度,我们
还将这个宽度称作对话框基本单位。对话框基本单位的具体量值可以
通过API函数GetDialogBaseUnits得到,该函数返回值的低位字代表
对话框水平基本单位,高位字代表对话框垂直基本单位。
紧接着我们调用了API函数EnumFontFamilies来枚举系统中的所有可
用字体,该函数使用4个参数,第一个参数为枚举所使用设备上下文
句柄,我们使用API函数GetDC来得到代表当前窗口的客户区;为了枚
举系统中的所有字体,我们将第二个参数设置为NULL;第三个参数为
枚举字体回调函数,这里为EnumFontFamProc,我们将在下面定义该
回调函数;第四个参数为指向列表框的指针,这个参数将被传递给回
调函数,由于我们需要将可用的字体添加到列表框中,因此我们可以
很自然的将指向该列表框指针当前应用程序提供的参数传递给枚举字
体回调函数。
枚举字体回调函数的原型在程序中被声明为
int WINAPI EnumFontFamProc(const LOGFONTA *lplf;
const TEXTMETRICA *lptm; unsigned long FontType; LPARAM lParam);
…………………………………………………………Page 563……………………………………………………………
l 注意:
l 在随Visual C++ 5。0提供的Platform SDK (即Win32 SDK)中所给
出的EnumFontFamProc的原型为
l int CALLBACK EnumFontFamProc( ENUMLOGFONT FAR *lpelf; // pointer to logical
font data
l NEWTEXTMETRIC FAR *lpntm; // pointer to physical…font data
l int FontType; // type of font
l LPARAM lParam // address of application…defined data
l );
然而在本程序中使用上面所给的原型将会在编译时导致类型
不匹配。正确的回调函数的原型应该如代码清单中所给的那
样。
图9。 7 示例程序FontDemo的运行结果
在本程序中,传递给回调函数的第一个参数lplf为该字体对应的
LOGFONTA结构,最后一个参数为指向列表框的CListBox指针。第二个
参数和第三个参数在本程序中没有使用。在本程序中,枚举字体回调
函数的结构很简单,它只是将字体的字体名和相应的字符集格式化之
后添加到列表框中。为了使枚举继续进行,回调函数应该返回真值,
如果回调函数返回了FALSE,则枚举的过程将被终止。
示例程序FontDemo的运行结果如图9。7所示。
…………………………………………………………Page 564……………………………………………………………
在类CDC中定义的字体和文本函数如表所示。
表9。 5 在类CDC中定义的字体和文本函数
成员函数 描述
TextOut 在指定位置以当前选定字体绘制字符串
ExtTextOut 在指定的矩形区域内使用当前选定字体
绘制字符串
TabbedTextOut 以指定的位置绘制字符串,并按指定的
制表符位置扩展字符串的制表符
DrawText 在指定的矩形区域内绘制格式化文本
GetTextExtent 使用当前字体中属性设备上下文中计算
一行文本的宽度和高度
GetOutputTextExtent 在输出设备上下文中计算一字符串的宽
度和高度
GetTabbedTextExtent 在属性设备上下文中计算一字符串的宽
度和高度
GetOutputTabbedTextExtent 在输出设备上下文中计算一字符串的宽
度和高度
GrayString 在指定位置绘制变灰的文本
GetTextAlign 获得文本对齐标志
SetTextAlign 设置文本对齐标志
GetTextFace 将当前字体的字体名拷贝到缓冲区
GetTextMetrics 从属性设备上下文中获得当前字体的度
量值
GetOutputTextMetrics 从输出设备上下文中获得当前字体的度
量值
SetTextJustification 在字符串的分隔字符处添加空白
GetTextCharacterExtra 获得字符间空白的当前设置
SetTextCharacterExtra 设置字符间空白的当前设置
GetFontData 从可缩放字体文件中获取字体信息。所
获取的信息通过指定字体文件中的偏移
量和返回信息的长度来确定
…………………………………………………………Page 565……………………………………………………………
GetKerningPairs 在选定的设备上下文中获得当前选定字
体的字距调整字符对
GetOutlineTextMetrics 获得TrueType字体的字体度量信息
GetGlyphOutline 返回当前字体的字符的轮廓曲线或位图
GetCharABCWidths 从当前字体中以逻辑单位返回给定范围
的连续字符的宽度
GetCharWidth 从当前字体中返回给定范围的连续字符
的相对宽度
GetOutputCharWidth 从输出设备上下文中的当前字体返回连
续字符组中若干单个字符的宽度
续表9。5
成员函数 描述
SetMapperFlags 改变字体映射程序中从逻辑字符到物理字体
的映射过程中所使用的算法
GetAspectRatioFilter 获得当前纵横比过滤器的设定
在一些应用程序 (如字处理应用程序)中,我们一般需要由用户来指定
所使用的字体。这时常使用的方法是弹出一个字体对话框,用户通过
该字体对话框来设置应用程序所使用的字体。MFC类CFontDialog封装
了标准的Windows字体对话框。在最简单的情况下,我们只需要声明
一个类的实例对象CFontDialog,然后通过该对象调用类CFongDialog
的成员函数DoModal,如果该成员函数返回IDOK,则通过成员函数
GetCurrentFont将用户所选择的字体信息填入一个LOGFONT结构中,
在下面的过程中即可通过该结构创建CFont对象。在很多情况下,我
们需要为字体对话框设置一些初始值,一种很简单的方式在其构造函
数中传递一个指向LOGFONT结构对象的指针。我们可以在创建
CFontDialog对象之后,调用DoModal成员之前改变其类型为
CHOOSEFONT的成员结构m_cf的各成员的值来为字体对话框进行初始设
置。
9。4。4 创建特殊的字体效果
在一般的应用程序中,我们可以使用SetBkMode和SetBkColor来设置
绘制文本所使用的颜色和模式,但是,这两个函数所设置的效果是很
有限的。有时候我们可能希望得到一些特殊的文本输出效果。这时我
…………………………………………………………Page 566……………………………………………………………
们就应该考虑其它特殊的实现方式。使用路径是其中的一种方法。下
面我们讲述一些使用路径得到的特殊的字体效果。
(1) 空心字
在开始一个路径前,我们先调用CDC类的成员函数BeginPath,然后调
用一系列的输出函数,在完成绘制之后,我们可以调用CDC类的成员
函数EndPath。在完成一个路径之后,我们可以调用StrokePath来绘
制该路径。为了简单起见,我们仅给出应用程序的OnPaint成员函数
如下:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc。GetCurrentFont()…》GetLogFont(&lf);
CFont font;
CFont *pOldFont; // 保存设备上下文最初使用的字体对象
lf。lfCharSet=134;
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));
…………………………………………………………Page 567……………………………………………………………
CPen *pOldPen;
pOldPen=dc。SelectObject(&pen);
// 开始一个路径
dc。BeginPath();
dc。TextOut(10; 10; 〃空心字〃);
dc。EndPath();
// 绘制路径
dc。StrokePath();
// 恢复设备上下文的原有设置
dc。SelectObject(pOldFont);
dc。SelectObject(pOldPen);
}
上面的程序的运行结果如图9。8所示。
图9。 8 绘制空心字
函数FillPath可以使用当前刷子填充路径的内部。按下面的代码修改
前面的OnPaint成员函数:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
…………………………………………………………Page 568……………………………………………………………
LOGFONT lf;
dc。GetCurrentFont()…》GetLogFont(&lf);
CFont font; *pOldFont;
lf。lfCharSet=134;
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)); *pOldPen;
pOldPen=dc。SelectObject(&pen);
// 更改当前刷子
CBrush br(HS_DIAGCROSS; RGB(0; 255; 255)); *pOldBrush;
pOldBrush=dc。SelectObject(&br);
// 开始一个路径
dc。BeginPath();
dc。TextOut(10; 10; 〃空心字〃);
dc。EndPath();
// 绘制路径
dc。StrokeAndFillPath();
…………………………………………………………Page 569……………………………………………………………
图9。 9 使用刷子填充空心字的内部
// 恢复设备上下文的原有设置
dc。SelectObject(pOldFont);
dc。SelectObject(pOldPen);
dc。SelectObject(pOldBrush);
}
上面的程序的运行结果如图9。9所示。
(2) 渐变字
在完成一个路径之后,如前所述,我们可以调用CDC类的成员函数
FillPath、StrokePath或StrokeAndFillPath来绘制和填充路径。这
只是最初级的技巧。更进一步,我们可以使用成员函数
SelectClipPath将路径选入当前剪辑区域,这样,所有的绘制操作都
将只作用于这个剪辑区域。
使用此技巧可以绘制具有渐变颜色效果的字体。如下面的OnPaint成
员函数所示:
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc。GetCurrentFont()…》GetLogFont(&lf);
…………………………………………………………Page 570……………………………………………………………
CFont font; *pOldFont;
lf。lfCharSet=134;
lf。lfHeight=…150;
lf。lfWidth=0;
strcpy(lf。lfFaceName; 〃隶书〃);
font。CreateFontIndirect(&lf);
pOldFont=dc。SelectObject(&font);
dc。SetBkMode(TRANSPARENT);
// 更改当前画笔为空
CPen pen(PS_NULL; 1; RGB(255; 0; 0)); *pOldPen;
pOldPen=dc。SelectObject(&pen);
// 更改当前刷子
CBrush br(0); *pOldBrush;
pOldBrush=dc。SelectObject(&br);
// 开始一个路径
dc。BeginPath();
dc。TextOut(10; 10; 〃渐变字〃);
dc。EndPath();
// 绘制渐变效果
dc。SelectClipPath(RGN_COPY);
for (int i=255; i》0; i……)
{
int iRadius=(600*i)/255;
dc。SelectObject(pOldBrush);
br。DeleteObject();
br。CreateSolidBrush(RGB(255; i; 0));
…………………………………………………………Page 571……………………………………………………………
dc。SelectObject(&br);
dc。Ellipse(…iRadius; …iRadius/3; iRadius; iRadius/3);
}
// 恢复设备上下文的原有设置
dc。SelectObject(pOldFont);
dc。SelectObject(pOldPen);
dc。SelectObject(pOldBrush);
}
在上面的示例中,我们以RGN_COPY方式将路径选作当前剪辑区域,然
后,在该剪辑区域上进行一系列的绘制操作,这些绘制操作以不同的
颜色绘制了一系列的同心椭圆,这些同心椭圆有视觉上给用户以渐变
的感觉。上面的程序的运行结果如图。
图9。 10 绘制渐变字
(3) 使用不同的光栅模式创建特殊效果
光栅模式决定了画笔的颜色和屏幕上原有的点的颜色值在进行绘制时
的组合方式。可以使用类CDC的成员函数SetROP2来设置设备上下文所
使用的光栅绘制模式。该操作仅对光栅设备起作用。通过指定不同的
光栅模式,我们可以制造一些特殊的效果,比如说反色字等。
下面的OnPaint处理函数演示了16种不同的光栅模式,需要注意的
是,即使是同一种光栅模式,在当前画笔的颜色不同时所产生的结果
也可能有很大差异。
// 应用程序主窗口的重绘函数
void CMyWnd::OnPaint()
{
…………………………………………………………Page 572……………………………………………………………
// 获得窗口的客户区设备上下文句柄
CPaintDC dc(this);
// 更改当前字体
LOGFONT lf;
dc。GetCurrentFont()…》GetLogFont(&lf);
CFont font1; font2; *pOldFont;
lf。lfCharSet=134;
lf。lfWidth=0;
lf。lfHeight=…12;
strcpy(lf。lfFaceName; 〃宋体〃);
font2。CreateFontIndirect(&lf);
lf。lfHeight=…50;
lf。lfWeight=1000;
strcpy(lf。lfFaceName; 〃黑体〃);
font1。CreateFontIndirect(&lf);
pOldFont=dc。SelectObject(&font1);
dc。SetBkMode(TRANSPARENT);
// 更改当前画笔为空
CPen pen1(PS_NULL; 1; RGB(0; 0; 0)); pen2(PS_SOLID; 1; RGB(0; 0; 0)); *pOldPen;
pOldPen=dc。SelectObject(&pen1);
// 更改当前刷子
CBrush br(RGB(0; 0; 255)); *pOldBrush;
pOldBrush=dc。SelectObject(&br);
// 绘制背景
for (int i=0; i
快捷操作: 按键盘上方向键 ← 或 → 可快速上下翻页 按键盘上的 Enter 键可回到本书目录页 按键盘上方向键 ↑ 可回到本页顶部!
温馨提示: 温看小说的同时发表评论,说出自己的看法和其它小伙伴们分享也不错哦!发表书评还可以获得积分和经验奖励,认真写原创书评 被采纳为精评可以获得大量金币、积分和经验奖励哦!