再上一篇:15.5 GDI与文本处理
上一篇:15.6 CString类
主页
下一篇:15.8 菜单的制作
再下一篇:附录A ASCII码表
文章列表

15.7 文本处理

《VC++程序设计基础》,讲述C++语言的语法和标准库,以及Visual C++ 函数库和MFC类库的使用,并附相关代码示例。

文本是由窗口客户区管理的,文本输出的外观受限于可用字体数目及输出设备的色彩能力。CDC提供了丰富的成员函数用于处理文本。

15.7.1 输出文本函数

CDC类提供了4种8个成员函数用于输出文本,在此只介绍其中的一种:

virtual BOOL TextOut(int x,int y, LPCSTR lpszString, int nCount);

BOOL TextOut(int x,int y, const CSTring &str);

函数TextOut输出文本的内容,x和y指定文本输出的开始位置,nCount指定字符串长度,lpszString 为指向要输出字符串的指针,str为包含要输出字符串的CString对象。输出成功,函数返回1,否则返回0。

15.7.2 设置文本属性

在没有设置文本属性的前题下,成员函数TextOut在输出文本时,显示文本的背景为白色,输出字符的颜色为黑色。通过设置文本属性,可以指定输出字符的颜色、字符串的对齐方式和字符间的间隔。有三个成员函数用于设置文本属性:

virtual COLORREF SetTextColor(COLORREF crColor);

该函数设置文本输出的颜色,crColor 指定文本颜色的RGB值。

UINT SetTextAlign(UINT nFlags);

该函数设置文本对齐标记。函数TextOut按设置的对齐标记来显示文本,表 15-12给出了nFlags的取值和作用。

表15-12 文本对齐方式

文本对齐标志值 作用

TA_CENTER 将点同边界矩形的水平中心对齐

TA_LEFT 将点同边界矩形的左边界对齐

TA_RIGHT 将点同边界矩形的右边界对齐

TA_BASELINE 将点同所选字体的基线对齐

TA_BOTTOM 将点同边界矩形的底线对齐

TA_TOP 将点同边界矩形的顶边对齐

TA_NOUPDATECP 调用文本输出函数之后,不更新当前位置

TA_UPDATECP 调用文本输出函数之后,更新当前位置

int SetTextCharacterExtra(int nCharExtra);

该函数设置字符间的间隔值。nCharExtra指定间隔值。

15.7.3 获取字符属性

在WINDOWS操作系统中,不同ASII码字符的大小是不同的。例如,字符i和m的宽度不同。每一个字符的高度和基线以上部分的长度也不同,例如字符b和g。另外,可以设置不同的的行距和间距。字符的这些特性称为字符的基本属性。

使用CDC的成员函数GetTextMetrics可以得到当前字体的完整描述,该函数的原型为: BOOL GetTextMetrics(LPTEXTMETRIC lpMetric);

其中参数lpMetric为指向结构体TEXTMETRIC的指针,该结构体的定义为:

typedef struct tagTEXTMRTRIC{

int tmHeight; //字符的高度

int tmAscent; //字符的上升高度(高于基线部分)

int tmDecent; //字符的下降高度(低于基线部分)

int tmInternalLeading; //字体的点尺寸与物理尺寸的差别

int tmExternalLeading; //二行之间的间隔

int tmAveCharWidth; //所有字符的平均高度

int tmMaxCharWidth; //最宽字符的最大宽度

int tmWeight; //字符的重量

BYTE tmItalic; //非0表示斜体

BYTE tmUnderlined; //非0表示有下划线

BYTE tmStruckOut; //非0表示带有删除线

BYTE tmFirstChar; //首字符值

BYTE tmLastChar; //尾字符值

BYTE tmDefautChar; //缺省的字符值

BYTE tmBreakChar; //中断字符值

BYTE tmPichAndFamily; //字体间距和族

BYTE tmCharSet; //字符集

int tmOverhang; //某些合成字符上的额外宽度

int tmDigitizedAspectX; //设备的水平特性

int tmDigitizedAspectY; //设备的垂直特性

}TEXTMETRIC , *LPTEXTMETRIC;

我们不对每一个属性作说明,主要说明两个重要的属性 tmExternalLeading(行距)和tmHeight(字符高度)。知道这两个属性值,可以在不关心字体及字体大小的情况下,根据当前输出行的行距和字符高度,确定下一行文本输出的位置。

在输出中文汉字时,每一个字的宽度是相同的,但输出西文字符串时,由于不同字符具有不同的宽度,在输出一个字符串时要知道该字符串占用的宽度,以便确定在下一行输出字符串的位置。CDC的成员函数GetTextExtent可用来计算要输出字符串的宽度。函数原型为:

CSize GetTextExtent(LPCSTR lpszString, int nCount);

CSize GetTextExtent(const CString &str);

其中lpszString为指向字符串的指针,nCount为要输出的字符个数,str为包含一个字符串的CString对象。类型CSize有两个数据成员cx和cy,用于存放字符串的宽度和高度值。知道了字符串的宽度,才能确定在该行接着输出字符串的开始位置。

15.7.4 使用字体

输出字符时,不仅要确定字符的大小,还要确定使用的字体。WINDOWS提供 6种基本字体库,可使用其中的某一种字体来输出字符。用户也可以根据需要创建自己的字体。要选择基本字体库中的某一种字体时,可使用CDC的成员函数SelectStockObject来实现,其参数取值为以下六个宏之一:

ANSI_FIXED_FONT // ANSI固定字体

ANSI_VAR_FONT // ANSI可变字体

DEVICE_DEFAULT_FONT //设备缺省的字体

OME_ FIXED_FONT //OME的固定字体

SYSTEM_FONT //系统字体

SYSTEM_FIXED_FONT //系统固定的字体

例如,SelectStockObject(ANSI_FIXED_FONT)表示选用ANSI固定字体。

在MFC类库中,CFont类封装了GDI的字体对象,用其成员函数CreateFont可根据用户需求创建一种字体。该成员函数的原型为:

BOOL CreateFont(int nHeight,int nWidth,int nEscapement,

int nOrientation,int nWeight, BYTE bItalic, BYTE bUnderline,

BYTE cStrickOut,BYTE nCharSet,BYTE nOutPrecition,

BYTE nClipPrecition, BYTE nQuality, BYTE nPichAndFamily,

LPCSTR lpszFacename);

其中参数nHeight为字体的高度;nWidth为字体的宽度,若其值为0,则根据当前方向比率选择最佳值;nEscapement指定文本显示的角度,值0为水平,900为垂直输出,其递增单位为1/10度;nOrientation指定字体的角度,即与水平方向的角度,其递增单位为1/10度;nWeight为字体的磅数,其取值范围为0~1000,缺省值为0,一般的字体为400,值越大字体越粗;bItalic取0时为非斜体,否则为斜体;bUnderline取0时不带下划线,否则带下划线;cStrickOut取0时为不带删除线,否则带删除线;nCharSet用于指定字体集,其取值可为ANSI_CHARSET、DEFAULT_CHARSET、SYMBOL_CHARSET、SHIFTS_CHARSET或OME_CHARSET;nOutPrecition指定输出的精度;nClipPrecition指定裁剪精度;nQuality指定逻辑字体与输出设备提供的实际字体之间的精度,其取值可以是DEFAULT_QUALITY、DRAFT_QUALITY或PROOF_QUALITY;nPichAndFamily指定字体的间距和字体族,间距的取值为 DEFAULT_PITCH、FIXED_PITCH 或 VARABLE_PITCH,字体族的取值为FF_DECORATIVE、FF_DONTCARE、FF_MODERN、FF_ROMAN、FF_SCRIPT或FF_SWISS,间距和字体族之间用按位或表示,例如,DEFAULT_PITCH | FF_ROMAN;lpszFacename是字体的名字,其长度应小于30(至多30个字符)。

例15.1 使用同一种字体,以不同的字符大小输出同一文本信息。

使用MFC AppWizard 生成一个项目ch1002,选择单文档界面,其它均取缺省值。在视图窗口中输出字符串时,要产生或选择字体,并设置映射模式。为此,在文件 ch1002View.h的类CCh1002View中增加两个成员函数。

class CCh1002View : public CView

{ ……

// Operations

private:

void ShowFont(CDC *,int &,int );//产生字体

protected:

void OnPrepareDC(CDC *pDC,CPrintInfo *pInfo=NULL);//设置映射模式

……

};

在文件ch1002View.cpp中增加这二个成员函数的实现部分:

void CCh1002View::OnPrepareDC(CDC *pDC,CPrintInfo *pInfor)

{

pDC->SetMapMode(MM_ANISOTROPIC);//设置映射模式

pDC->SetWindowExt(1400,1400); //设置窗口大小

pDC->SetViewportExt(pDC->GetDeviceCaps(LOGPIXELSX),

-pDC->GetDeviceCaps(LOGPIXELSY)); //设置视口的大小

}

void CCh1002View::ShowFont(CDC *pDC,int &nPos,int nPoints)

{

TEXTMETRIC tm;

CFont NewFont;

char psOrigin[100];

//创建字体

NewFont.CreateFont (-nPoints*20,0,0,0,FW_BOLD,true,false,false,

ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY,DEFAULT_PITCH|FF_SWISS,"Times New Roman");

//装入新字体,保存原字体

CFont *pOldFont=(CFont *)pDC->SelectObject(&NewFont);

pDC->GetTextMetrics(&tm); //获取字体属性

wsprintf(psOrigin,"This is %d-point Times New Roman 中国北京。",nPoints);

CString str(psOrigin);//将psOrigin中的字符串放入CString对象str中

pDC->TextOut(0,nPos,str); //输出字符串

pDC->SelectObject(pOldFont); //恢复原来的字体

nPos -= tm.tmHeight + tm.tmExternalLeading; //计算出下一行的y轴坐标};

函数 OnPrepareDC是重载的虚函数。在调用 OnDraw 之前系统首先要调用成员函数OnPrepareDC,该函数调用SetMapMode将映射模式设置为非约束的MM_ANISOTROPIC,这种映射模式由系统根据窗口大小和视口大小来计算出两种坐标之间的比例因子,见表15-11。为此,要调用SetWindowExt来设置窗口的大小,调用SetViewportExt来设置视口的大小。注意,视口与视图窗口是二个不同的对象。当视口大小固定时,随着窗口大小的增大,在视口中显示的字符而缩小(比例因子变小)。成员函数 GetDeviceCaps(LOGPIXELSX)和GetDeviceCaps(LOGPIXELSY)分别得到设备在x和y方向的大小,y方向的大小取负数是因为MM_ANISOTROPIC映射模式的y轴方向向上,而窗口的y轴方向向下。

函数ShowFont要完成创建字体,并将其放入设备场境中,再在视图窗口中显示一行字符串,然后释放并删除字体。函数CreateFont的参数中,最主要的参数是前两个:字体的高度和宽度。每次调用ShowFont时,其高度是递增的。若希望按指定大小的字体输出字符串,则参数字体的高度应为负数(两坐标体系的y方向正好相反)。在函数wsprintf中的%d表示将整数nPoints转换成对应的ASCII字符序列后,插入到%d的位置,例如,设nPoints的值为16,经转换后的字符串为:

"This is 16-point Times New Roman 中国北京。"

然后将这字符串拷贝到psOrigin中。

修改在文件 ch1002View.cpp中的成员函数 OnDraw,用一个循环语句调用函数ShowFont,输出同一字符串,但每一次产生的字体高度不同。

void CCh1002View::OnDraw(CDC* pDC)

{

CCh1002Doc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

int nPosition =0;

for(int i=6;i<24; i+=2)

ShowFont(pDC,nPosition, i);

}

没有经过坐标的比例因子变换时,每一行字符的高度为i *20个像素。

例15.2 更改字体的宽度并用几种字体输出字符串。

使用MFC AppWizard 生成一个项目ch1003,选择单文档界面,其它项目取缺省值。在文件ch1003View.h的类CCh1002View中增加一个成员函数OnPrepareDC:

class CCh1003View : public CView

{ ……

protected:

void OnPrepareDC(CDC *pDC,CPrintInfo *pInfo=NULL);

……

};

在文件ch1002View.cpp中增加该函数的实现部分:

void CCh1003View::OnPrepareDC(CDC *pDC,CPrintInfo *pInfor)

{

RECT theRect;

GetClientRect(&theRect);

pDC->SetMapMode(MM_ANISOTROPIC);

pDC->SetWindowExt(400,400);

pDC->SetViewportExt(theRect.right,-theRect.bottom);

}

在这个函数中,使用函数GetClientRect来获得视图窗口的矩形区大小,然后将这矩形区的宽度和高度作为设置视口的大小。

修改在文件ch1002View.cpp中的OnDraw函数为:

void CCh1003View::OnDraw(CDC* pDC)

{

CCh1003Doc* pDoc = GetDocument();

ASSERT_VALID(pDoc);

// TODO: add draw code for native data here

CFont NewFont[4];

CString str[4];

str[0]="中国This is Bookman Old style,default width.";

str[1]="中国This is Courier,default width.";

str[2]="中国This is Liberate,default width.";

str[3]="中国This is generic Roman,variable width.";

NewFont[0].CreateFont (50,0,0,0,400,false,false,false,

ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY,DEFAULT_PITCH|FF_SWISS,"Bookman Old style");

CFont *pOldFont = pDC->SelectObject(&NewFont[0]);

pDC->TextOut (0,0, str[0]);

NewFont[1].CreateFont (50,0,0,0,400,false,false,false,

ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY,DEFAULT_PITCH|FF_MODERN,"Courier");

pDC->SelectObject(&NewFont[1]);

pDC->TextOut (0,-100, str[1]);

NewFont[2].CreateFont (50,0,0,0,400,false,false,false,

ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY,DEFAULT_PITCH|FF_SCRIPT,"Liberate");

pDC->SelectObject(&NewFont[2]);

pDC->TextOut (0,-200, str[2]);

NewFont[3].CreateFont (50,10,0,0,400,false,false,false,

ANSI_CHARSET,OUT_DEFAULT_PRECIS,CLIP_DEFAULT_PRECIS,

DEFAULT_QUALITY,DEFAULT_PITCH|FF_ROMAN,"Roman");

pDC->SelectObject(&NewFont[3]);

pDC->TextOut (0,-300, str[3]);

pDC->SelectObject(pOldFont);

}

该函数分别产生了四种字体,用每一种字体输出一个字符串。编译、连接并执行这个应用程序,看看这四种字体的输出效果。第四种字体的输出随窗口的大小变化而变化(字体的宽度可变)。