1
第 5讲 文本与字体
使用定义好的与设备无关的 字体 集,Windows就能维
护它的设备无关性,提供,所见即所得,的好处,即屏幕
所见与设备输出的文本是一样的
Windows经常使用
GDI进行文本输出。在
一定意义上,任何内容
都可以看成 图形实体
图形和文本并
没有明显的界限
文本
操作
先要获得文本句柄
设置字体、字符大小、字符颜色等有关属性
将这些属性选入设备环境
2
5.1 设置文本的设备环境
字体
逻辑字体 定义的字符集是 设备无关 的,它可以精确标度,因
此得到广泛应用
描述所要显示
的文本的大小、
类型和外形
物理字体 是为特殊设备设计的,因而是 设备相关 的
Win 系统
提供了七种
基本字体
字体 说明
ANSI_FIXED ANSI标准的 固定 宽度的字体
ANSI_VAR ANSI标准的 可变 宽度的字体
DEFAULT_GUI 当前 GUI的缺省字体
OEM_FIXED 由标准原设备制造商 (OEM)提供
DEVICE_DEFAULT 当前图形设备的字体
SYSTEM_FIXED Windows的标准 固定 宽度的字体
SYSTEM Windows提供的 可变 宽度的字体
常作为缺省字体
Win用它作为
系统界面字体
3
(1) 定义字体句柄变量:
HFONT hF; //hF为字体的句柄
(2) 调函数 GetStockObject获得系统字体句柄
它返回的是系统的缺省字体
hF= GetStockObject( ):
(3) 调用函数 SelectObject将字体选入设备环
境
SelectObject(hdc,hF);
选
择
系
统
字
体
的
步
骤
4
5.1.2 创建自定义字体
若需要定义系统以外的字体,可以调用函数 GreateFont自行 创建
HFont=CreateFont
(int nHeight,//字体高度,0采用系统缺省值,使用逻辑单位
int nWidth,//字体宽度,取 0则由系统根据高宽比取最佳值
int nEscapement,//每 行 文字相对于页底的角度,单位为 0.1度
int nOrienation,//每 个 文字相对于页底的角度,单位为 0.1度
DWORD nWeight,//字体粗细度,范围为 0~ 1000
DWORD Dwltalic,//如果要求字体倾斜,则取非零
DWORD dwUnderline,//如果要求下划线,则取非零
DWORD dwStrikeout,//如果要求中划线,则取非零
DWORD dwCharset,//字体所属字符集
DWORD dwOutputPrecision,//输出精度,一般取缺省值 OUT_DEFAULT_PRECIS
DWORD dwClipPrecision,//剪裁精度,常取缺省值 CLIP_DEFAULT_PRECIS
DWORD dwQuality,//输出质量,一般取缺省值 DEFAULT_QUALITY
DWORD dwPitchAndFamily,//字体名
)
可选的系统字符集:
ANSI_CHARSET
OEM_CHARSET
SYMBOL_CHARSET
DEFAULT_CHARSET
SHIFTJIS_CHARSET
5
5.1.3 设置字体和背景颜色
设置字体颜色,SetTextColor(hdc,crColor);
设置背景颜色, SetBkColor(hdc,crColor);
crColor为设置的颜色
字体 及 背景颜色
的设置在开发过
程中非常重要
6
5.2 文本的输出过程
确定后续文本坐标
确定换行时文本坐标
文本输
出过程
获取字体信息
格式化文本
调用函数输出文本
7
获取字体信息
输出文本之前要获取字体的信息,如字符高度
等,以确定输出格式和下一行字符的位置
GetTextMetrics (hdc,&tm); //tm为 TEXTMETRICS结构
获取当前使
用字体信息
调用该函数时,系统将当前
字体的信息拷贝到 tm标识
的 TEXTMETRICS结构中
8
系统定义的 TEXTMETRICS的结构如下:
typedef struct tagTEXTMETRIC
{ //tm
LONG tmHeight; //字符高度
LONG tmAscent; //字符基线以上高度
LONG tmDescent; //字符基线以下高度
LONG tmInternalLeading; //tmHeight制订的字符高度顶部的控件
LONG tmExternalLeading; //行与行之间的间隔
LONG tmAveCharWidth; //平均字符宽度
LONG tmMaxCharWidth; //最大字符宽度
LONG tmWeight; //字符的粗细度
LONG tmOverhang; //合成字体间附加的宽度
LONG tmDigitizedAspectX; //为输出设备设计的 X轴尺寸
LONG tmDigitizedAspectY; //为输出设备设计的 Y轴尺寸
BCHAR tmFirstChar; //字体中第一个字符值
BCHAR tmLastChar; //字体中最后一个字符值
BCHAR tmDefaultChar; //代替不在字体中字符的字符
BCHAR tmBreakChar; //作为分割符的字符
BYTE tmItalic; //非 0则表示字体为斜体
BYTE tmUnderlined; //非 0则表示字体有下划线
BYTE tmStruckOut; //非 0则表示字符为删除字体
BYTE tmPitchAndFamily; //字体间距和字体族
BYTE tmCharSet; //字符集
}TEXTMETRIC
9
格式化文本
(1) 确定后续文本坐标
换行时确定下一行文本的坐标
需要格式化
处理的情况
在文本行中确定后续文本的坐标
确定后续文本的坐标,应先获取当前的字符串的宽度,该工作由
GetTextExtentPoint32函数 完成,并把它存储于一个 SIZE结构 中。
BooL GetTextExtentPoint32
(
HDC hdc,
LPCTSTR lpszString,//指定的字符串
int nLength,//字符串中的字符数
LPSIZE lpSize //返回字符串宽度及高度的 SIZE数据结构 的地址
)
SIZE数据结构 的定义
typedef struct tagSIZE
{ LONG cx;
LONG cy;
} SIZE;
例如,X轴起始坐标为 cx0,后续文本起始坐标 cx1为:
cx1=cx0+size.cx;
10
(2)确定换行时文本坐标
字符的高度 与 行间隔 均存储在 tm指向的 TEXTMETRICS结
构中,换行时 Y轴上文本的起始坐标 cy为:
cy=tm.tmHeight+tm.tmExternalLeading;
通过计算当前行文本 字符的高度 与 行间隔 之和,即可
得到换行时文本的起始坐标
11
文本输出
常用的文本输出函数 TextOut原型如下:
BOOL TextOut
(
HDC hdc,
int X,int Y,//X,Y为用户区中字符串的起始坐标
LPCTSTR lpstring,//lpstring为显示的字符串
int nCount //nCount为字符串中的字节数
);
TextOut 以坐标 X,Y为起点,
输出字节数为 nCount、
名为 lpstring中的字符串
12
5.3 文本操作实例
【 例 5-1】 在用户窗口上输出几行字符串,当窗口接收到
WM_PAINT消息后,显示的文本每次都被重新刷新。
#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(
HWND hWnd,
UINT iMessage,
UINT wParam,
LONG lParam
);
BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);
13
//主函数
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG Message;
if(!InitWindowsClass(hInstance)) return FALSE;
if(!InitWindows(hInstance,nCmdShow))return FALSE;
while(GetMessage(&Message,0,0,0))//消息循环
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
14
//消息处理函数
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
{
static long nXChar,nYChar;
HDC hDC; //定义指向设备上下文的句柄
short x;
TEXTMETRIC tm;
short LnCount=6;
PAINTSTRUCT PtStr; //定义指向包含绘图信息的结构体变量
static char *textbuf[]=
{
"This is the First line",
"This is the second line",
"This is the third line",
"This is the fourth line",
"This is the fifth line",
"This is the sixth line"
};
输出的文
本内容
15
switch(iMessage) //处理消息
{case WM_CREATE,//处理窗口创建消息
hDC=GetDC(hWnd) ; //获取当前设备表句柄
GetTextMetrics(hDC,&tm); //获取字体信息
nXChar=tm.tmAveCharWidth; //获取字符宽度
nYChar=tm.tmHeight+tm.tmExternalLeading;
ReleaseDC(hWnd,hDC); //释放当前设备句柄
return 0;
case WM_PAINT,//处理重画消息
hDC=BeginPaint(hWnd,&PtStr); //开始绘画
for(x=0;x<LnCount;x=x+1) //输出文本
TextOut(hDC,nXChar,nYChar*(1+x),textbuf[x],lstrlen(textbuf[x]));
EndPaint(hWnd,&PtStr);
return 0;
case WM_DESTROY,//结束应用程序
PostQuitMessage(0);
return 0;
default,//其他消息处理程序
return(DefWindowProc(hWnd,iMessage,wParam,lParam)) ;
}
}
16
BOOL InitWindowsClass(HINSTANCE hInstance) //初始化窗口类
{ WNDCLASS WndClass;
…………;
WndClass.style=CS_HREDRAW|CS_VREDRAW;
return RegisterClass(&WndClass);
}
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow) //初始化窗口
{ HWND hWnd;
hWnd=CreateWindow("WinText",//生成窗口
"文本显示示例程序 ",
WS_OVERLAPPEDWINDOW,
…….;
NULL);
if(!hWnd) return FALSE;
ShowWindow(hWnd,nCmdShow); //显示窗口
UpdateWindow(hWnd);
return TRUE;
}
17
【 例 5-2】 本程序通过在窗口中分五行分别显示五行
文本,以说明在窗口的用户区中输出文本的方法。
18
本例题的源代码如下:
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow)
{
HWND hwnd;
MSG Msg;
WNDCLASS wndclass;
char lpszClassName[] = "文本输出 ";
char lpszTitle[]= "EXAMPLE FOR THE TEXT OUTPUT";
wndclass.style = 0;
…………;
wndclass.lpszClassName = lpszClassName;
19
if( !RegisterClass( &wndclass))
{ MessageBeep(0);return FALSE; }
hwnd = CreateWindow
( lpszClassName,lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow( hwnd,nCmdShow);
UpdateWindow(hwnd);
while( GetMessage(&Msg,NULL,0,0))
{ TranslateMessage(&Msg); DispatchMessage(&Msg); }
return Msg.wParam;
}
20
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
HDC hdc;
HFONT hF_black,hF_big; //定义两种字体句柄
PAINTSTRUCT ps;
TEXTMETRIC tm; //定义一个 TEXTMETRIC结构,用以记录字体信息
char lpsz_1[]=这是一行红色的、字体为 SYSTEM_FONT的文字,红色代表未来。 ";
char lpsz_2[]=现在显示的是自定义字体,颜色为绿色,绿色代表生机勃勃。 ";
char lpsz_3[]=现在展现在您面前的是蓝色的粗体字,蓝色代表广阔的海洋和天空。 ";
char lpsz_4[]="当前字体为大号、斜体并带有下划线的文字。 ";
char lpsz_5[]="现在您掌握了字体的操作了吗?";
char lpsz_6[]="祝您成功 !";
int X=0,Y=0;
SIZE size; //定义一个 SIZE类型的结构
21
switch(message){
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
SetTextColor(hdc,RGB(255,0,0)); //设置文本颜色为红色
GetTextMetrics(hdc,&tm); //获取缺省字体,写入 tm结构中
TextOut(hdc,X,Y,lpsz_1,strlen(lpsz_1));//用当前字体输出文本
Y=Y+tm.tmHeight+100*tm.tmExternalLeading;
//计算换行时下一行文本的输出坐标
hF_black=CreateFont( //创建自定义字体
20,//字体的高度
0,//由系统根据高宽比选取字体最佳宽度值
0,//文本的倾斜度为 0,表示水平
0,//字体的倾斜度为 0
FW_HEAVY,//字体的粗度,FW_HEAVY为最粗
0,//非斜体字
0,//无下划线
0,//无删除线
ANSI_CHARSET,//表示所用的字符集为 ANSI_CHARSET
OUT_DEFAULT_PRECIS,//输出精度为缺省精度
CLIP_DEFAULT_PRECIS,//剪裁精度为缺省精度
DEFAULT_QUALITY,//输出质量为缺省值
DEFAULT_PITCH|FF_DONTCARE,//字间距和字体系列使用缺省值
"粗体字 " ); //字体名称
22
SetTextColor(hdc,RGB(0,255,0)); //设置文本颜色为绿色
SelectObject(hdc,hF_black); //将自定义字体选入设备环境
GetTextMetrics(hdc,&tm); //获取字体的信息,写入 tm结构中
TextOut(hdc,X,Y,lpsz_2,strlen(lpsz_2));//用当前字体输出文本
//换行继续输出文本,计算新行的起始 Y坐标位置
Y=Y+tm.tmHeight+10*tm.tmExternalLeading;
GetTextExtentPoint32(hdc,lpsz_2,strlen(lpsz_2),&size);
//获取字符串 /的宽度
SetTextColor(hdc,RGB(0,0,255)); //设置文本颜色为蓝色
TextOut(hdc,X,Y,lpsz_3,strlen(lpsz_3));//当前字体输出文本
Y=Y+tm.tmHeight+20*tm.tmExternalLeading;
23
hF_big=CreateFont //引入新字体
(
30,//字体高度
0,
0,
0,
FW_NORMAL,
1,//定义斜体
1,//定义输出时带下划线
0,
ANSI_CHARSET,//所使用的字符集
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
"大号字 "
);
24
SelectObject(hdc,hF_big);//将自定义字体选入设备环境
SetTextColor(hdc,RGB(155,155,155));//设置文本颜色
Y=Y+tm.tmHeight+20*tm.tmExternalLeading;
TextOut(hdc,X,Y,lpsz_4,strlen(lpsz_4));//输出文本
SetTextColor(hdc,RGB(255,0,0));//设置文本颜色为红色
Y=Y+tm.tmHeight+30*tm.tmExternalLeading;
TextOut(hdc,X,Y,lpsz_5,strlen(lpsz_5)); //输出文本
//在该行继续输出文本
GetTextExtentPoint32(hdc,lpsz_5,strlen(lpsz_5),&size);
//获取字符串的宽度
X=X+size.cx; //获取起始坐标
TextOut(hdc,X,Y,lpsz_6,strlen(lpsz_6)); //输出文本
EndPaint(hwnd,&ps);
break;
25
case WM_DESTROY:
DeleteObject(hF_black); //退出窗口时删除自定义字体
DeleteObject(hF_big);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
26
【 5-3】 在窗口中显示出 26个英文字母,从左向右 字母依次位置提高
10个象素单位,并且颜色变为红色,然后回到正常位置;当到达最右
端后改变方向从右向左依次变成红色并位置提高 10个象素单位。在窗
口的第二行显示 26个字母,字体从正常到斜体,颜色从黑色到天蓝色
不断变换。如图所示。
用 nChar标志红
色跳起字母在
26个字母的位置
用 bRight,bLeft标志当前
移动方向,初始化
bRight=TRUE,bLeft=FALSE
27
本例题要解决 动态显示 问题,
首先处理第一行字符:在 WM_PAINT消息处理程序中,在得到了设
备环境句柄 hDC后,调用用户自定义的函数
CreateFont(hDC,nHeight,bItalic),第一个参数 hDC是设备环境
句柄,第 2个参数 nHeight是字体高度,第 3个参数 bItalic是斜字
体的标志变量
WM_CREATE
消息处理程序 定时器
调用 SetTimer(… )创建
WM_TIMER
消息处
理程序
调用 InvalidateRect(… )刷新
用户区 发送 WM_PAINT消息 实现动态
显示
28
下面这段程序按照黑色的字体输出从字符串开头到当前位置的字符串:
Y=tm.tmExternalLeading+10; //设置输出字符的 Y坐标
for(i=0;i<nChar;i++)
{SetTextColor(hDC,RGB(0,0,0)); //设置字体的颜色为黑色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X坐标
TextOut(hDC,X,Y,&lpsz_1[i],1);//输出从第 0个到第 nChar-1个字符
}
下面输出当前位置上的字符,当前位置的字符位置提高 10个象素单位,
字体颜色为红色:
SetTextColor(hDC,RGB(255,0,0));//设置字体的颜色为红色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X,Y坐标
Y=tm.tmExternalLeading; //提高 10个像素
hF = CreateFont(hDC,40,0); //创建字体
SelectObject(hDC,hF); //选入字体
TextOut(hDC,X,Y,&lpsz_1[nChar],1);//输出第 nChar个字符
Y=tm.tmExternalLeading+10;
for(i=nChar+1;i<nCharlen;i++)
{ SetTextColor(hDC,RGB(0,0,0)); //设置字体的颜色为黑色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X坐标
TextOut(hDC,X,Y,&lpsz_1[i],1); //输出后面的字符
}
29
下面设置 bRight和 bLeft的值。
if(nChar == nCharlen) //当输出到最后的一个字符时
{
bRight = FALSE; //改变红色字移动的方向为向左
bLeft = TRUE;
}
else(nChar == 0) //当输出到第一个字时
{
bRight = TRUE; //改变红色字移动的方向为向右
bLeft = FALSE;
}
if(bRight == TRUE) nChar++;
else nChar--;
如果 nChar==等于字符串长度 =〉 已到了字符串末尾,将 bRight置为 True
字符长度 ==0时,已到了最左端,将 bLeft置为 True;
当 bRight=True时字符位置标志 nChar加 1,当 bLeft=True时,字符位置标
志变量减 1。
30
下面输出第 2行字符:在 WM_PAINT处理程序中,加入下列代码:
hF = CreateFont(hDC,40,bItalic); //创建字体,大小为 40
SelectObject(hDC,hF); //选入字体
X = tm.tmAveCharWidth*2; //设置输出位置
Y = tm.tmHeight*2;
if(bItalic == TRUE)
SetTextColor(hDC,RGB(0,0,0));
else
SetTextColor(hDC,RGB(0,255,255));
TextOut(hDC,X,Y,lpsz_1,strlen(lpsz_1)); //输出
if(bItalic == TRUE)
bItalic=FALSE;
else
bItalic=TRUE;
调用用户自定义函数 CreateFont(… )创建斜体字,确定输出位置
根据 bItalic的状态设置字体的颜色。
当 bItalic为真时,输出斜体天蓝色字符;为假时,输出正常黑色字体
最后对 bItalic取反,在下一次显示与此次不同的另一种效果。
31
【 例 5-4】 将一首四句的古诗从右到左竖排输出。要求窗口每次接收
到 WM_PAINT消息时都刷新显示的文本。
32
#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam);
BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);
//主函数
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow)
{
MSG Message;
if(!InitWindowsClass(hInstance)) return FALSE;
if(!InitWindows(hInstance,nCmdShow)) return FALSE;
while(GetMessage(&Message,0,0,0)) //消息循环
{TranslateMessage(&Message);
DispatchMessage(&Message); }
return Message.wParam;
}
33
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
1,{ static long nXChar,nCaps,nYChar;
2,int pointx,pointy,int i,j;
3,HDC hDC; //定义指向设备环境的句柄
4,TEXTMETRIC tm; //存放字体各种属性的结构体变量
5,PAINTSTRUCT PtStr; //指向包含绘图信息的结构体变量
6,static char *textbuf[4]={{"故人西辞黄鹤楼 "},{"烟花三月下扬州 "},
{"孤帆远影碧空尽 "},{"唯见长江天际流 "}};
7,switch(iMessage) //处理消息
8,{ case WM_CREATE,//处理窗口创建消息
9,hDC=GetDC(hWnd) ; //获取当前设备表句柄
10,GetTextMetrics(hDC,&tm); //获取字体信息
11,nXChar=tm.tmAveCharWidth; //获取字符宽度
12,nYChar=tm.tmHeight+tm.tmExternalLeading; //字符高度
13,nCaps=(tm.tmPitchAndFamily&1?3:2)*nXChar/2; //字间距
14,ReleaseDC(hWnd,hDC); return 0; //释放当前设备句柄
15,case WM_PAINT,//处理重画消息
16,hDC=BeginPaint(hWnd,&PtStr); //开始绘图
17,for(i=4;i>0;i--)
18,{for(j=0;j<7;j++) //输出文本
19,{ pointx=100+i*nXChar*5; pointy=50+j*(nYChar+nCaps);
20,TextOut(hDC,pointx,pointy,textbuf[4-i]+j*2,2); } }
21,EndPaint(hWnd,&PtStr); return 0; //结束绘图
22,case WM_DESTROY,//结束应用程序
PostQuitMessage(0); return 0;
23,default,return(DefWindowProc(hWnd,iMessage,wParam,lParam));}}
34
【 例 5-5】 创建自定义字体的例 题 程序 。在窗口中
显示, 自定义的字体,,字体颜色为红色,
背景色为蓝色。其运行结果应如下图所示:
35
LRESULT CALLBACK WndProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
1,{HDC hdc ; //设备句柄
2,PAINTSTRUCT ps ; //画刷结构
3,int Xchar,Ychar;
4,SIZE size;
5,LPCTSTR *pstring=,自定义的字体, ;
6,RECT rect ; //无效矩形区
7,HFONT holdFont,hnewFont;
8,switch (message) //消息处理函数
9,{case WM_CREATE,return 0; //窗口创建
10,case WM_PAINT,//绘制消息
11,hnewFont=CreateFont //创建一种新的逻辑字体
12,( 64,0,0,0,500,0,0,0,
13,GB2312_CHARSET,
14,OUT_DEFAULT_PRECIS,
15,CLIP_DEFAULT_PRECIS,
16,DEFAULT_QUALITY,
17,DEFAULT_PITCH & FF_DONTCARE,
18.,黑体, );
36
19,hdc=BeginPaint (hwnd,&ps); //得到设备环境句柄
20,GetClientRect (hwnd,&rect); //得到需要绘制的客户区
21,holdFont=(HFONT)SelectObject(hdc,hnewFont); //选择新的字体
22,SetTextColor(hdc,RGB(255,0,0)); //设置文本颜色
23,SetBkColor(hdc,RGB(0,0,255)); //设置背景颜色
24,GetTextExtentPoint32(hdc,pstring,12,&size);
25,Xchar=(rect.right-rect.left)/2-size.cx/2;
26,Ychar=(rect.bottom-rect.top)/2-size.cy/2;
27,TextOut(hdc,Xchar,Ychar,pstring,12);
28,SelectObject(hdc,holdFont); //保存原来的字体格式
29,DeleteObject(hnewFont); //删除新的字体格式
30,EndPaint (hwnd,&ps) ; //结束绘制
return 0 ;
case WM_DESTROY,//退出消息
PostQuitMessage (0) ; return 0 ;
}
return DefWindowProc(hwnd,message,wParam,lParam) ;
}
第 5讲 文本与字体
使用定义好的与设备无关的 字体 集,Windows就能维
护它的设备无关性,提供,所见即所得,的好处,即屏幕
所见与设备输出的文本是一样的
Windows经常使用
GDI进行文本输出。在
一定意义上,任何内容
都可以看成 图形实体
图形和文本并
没有明显的界限
文本
操作
先要获得文本句柄
设置字体、字符大小、字符颜色等有关属性
将这些属性选入设备环境
2
5.1 设置文本的设备环境
字体
逻辑字体 定义的字符集是 设备无关 的,它可以精确标度,因
此得到广泛应用
描述所要显示
的文本的大小、
类型和外形
物理字体 是为特殊设备设计的,因而是 设备相关 的
Win 系统
提供了七种
基本字体
字体 说明
ANSI_FIXED ANSI标准的 固定 宽度的字体
ANSI_VAR ANSI标准的 可变 宽度的字体
DEFAULT_GUI 当前 GUI的缺省字体
OEM_FIXED 由标准原设备制造商 (OEM)提供
DEVICE_DEFAULT 当前图形设备的字体
SYSTEM_FIXED Windows的标准 固定 宽度的字体
SYSTEM Windows提供的 可变 宽度的字体
常作为缺省字体
Win用它作为
系统界面字体
3
(1) 定义字体句柄变量:
HFONT hF; //hF为字体的句柄
(2) 调函数 GetStockObject获得系统字体句柄
它返回的是系统的缺省字体
hF= GetStockObject( ):
(3) 调用函数 SelectObject将字体选入设备环
境
SelectObject(hdc,hF);
选
择
系
统
字
体
的
步
骤
4
5.1.2 创建自定义字体
若需要定义系统以外的字体,可以调用函数 GreateFont自行 创建
HFont=CreateFont
(int nHeight,//字体高度,0采用系统缺省值,使用逻辑单位
int nWidth,//字体宽度,取 0则由系统根据高宽比取最佳值
int nEscapement,//每 行 文字相对于页底的角度,单位为 0.1度
int nOrienation,//每 个 文字相对于页底的角度,单位为 0.1度
DWORD nWeight,//字体粗细度,范围为 0~ 1000
DWORD Dwltalic,//如果要求字体倾斜,则取非零
DWORD dwUnderline,//如果要求下划线,则取非零
DWORD dwStrikeout,//如果要求中划线,则取非零
DWORD dwCharset,//字体所属字符集
DWORD dwOutputPrecision,//输出精度,一般取缺省值 OUT_DEFAULT_PRECIS
DWORD dwClipPrecision,//剪裁精度,常取缺省值 CLIP_DEFAULT_PRECIS
DWORD dwQuality,//输出质量,一般取缺省值 DEFAULT_QUALITY
DWORD dwPitchAndFamily,//字体名
)
可选的系统字符集:
ANSI_CHARSET
OEM_CHARSET
SYMBOL_CHARSET
DEFAULT_CHARSET
SHIFTJIS_CHARSET
5
5.1.3 设置字体和背景颜色
设置字体颜色,SetTextColor(hdc,crColor);
设置背景颜色, SetBkColor(hdc,crColor);
crColor为设置的颜色
字体 及 背景颜色
的设置在开发过
程中非常重要
6
5.2 文本的输出过程
确定后续文本坐标
确定换行时文本坐标
文本输
出过程
获取字体信息
格式化文本
调用函数输出文本
7
获取字体信息
输出文本之前要获取字体的信息,如字符高度
等,以确定输出格式和下一行字符的位置
GetTextMetrics (hdc,&tm); //tm为 TEXTMETRICS结构
获取当前使
用字体信息
调用该函数时,系统将当前
字体的信息拷贝到 tm标识
的 TEXTMETRICS结构中
8
系统定义的 TEXTMETRICS的结构如下:
typedef struct tagTEXTMETRIC
{ //tm
LONG tmHeight; //字符高度
LONG tmAscent; //字符基线以上高度
LONG tmDescent; //字符基线以下高度
LONG tmInternalLeading; //tmHeight制订的字符高度顶部的控件
LONG tmExternalLeading; //行与行之间的间隔
LONG tmAveCharWidth; //平均字符宽度
LONG tmMaxCharWidth; //最大字符宽度
LONG tmWeight; //字符的粗细度
LONG tmOverhang; //合成字体间附加的宽度
LONG tmDigitizedAspectX; //为输出设备设计的 X轴尺寸
LONG tmDigitizedAspectY; //为输出设备设计的 Y轴尺寸
BCHAR tmFirstChar; //字体中第一个字符值
BCHAR tmLastChar; //字体中最后一个字符值
BCHAR tmDefaultChar; //代替不在字体中字符的字符
BCHAR tmBreakChar; //作为分割符的字符
BYTE tmItalic; //非 0则表示字体为斜体
BYTE tmUnderlined; //非 0则表示字体有下划线
BYTE tmStruckOut; //非 0则表示字符为删除字体
BYTE tmPitchAndFamily; //字体间距和字体族
BYTE tmCharSet; //字符集
}TEXTMETRIC
9
格式化文本
(1) 确定后续文本坐标
换行时确定下一行文本的坐标
需要格式化
处理的情况
在文本行中确定后续文本的坐标
确定后续文本的坐标,应先获取当前的字符串的宽度,该工作由
GetTextExtentPoint32函数 完成,并把它存储于一个 SIZE结构 中。
BooL GetTextExtentPoint32
(
HDC hdc,
LPCTSTR lpszString,//指定的字符串
int nLength,//字符串中的字符数
LPSIZE lpSize //返回字符串宽度及高度的 SIZE数据结构 的地址
)
SIZE数据结构 的定义
typedef struct tagSIZE
{ LONG cx;
LONG cy;
} SIZE;
例如,X轴起始坐标为 cx0,后续文本起始坐标 cx1为:
cx1=cx0+size.cx;
10
(2)确定换行时文本坐标
字符的高度 与 行间隔 均存储在 tm指向的 TEXTMETRICS结
构中,换行时 Y轴上文本的起始坐标 cy为:
cy=tm.tmHeight+tm.tmExternalLeading;
通过计算当前行文本 字符的高度 与 行间隔 之和,即可
得到换行时文本的起始坐标
11
文本输出
常用的文本输出函数 TextOut原型如下:
BOOL TextOut
(
HDC hdc,
int X,int Y,//X,Y为用户区中字符串的起始坐标
LPCTSTR lpstring,//lpstring为显示的字符串
int nCount //nCount为字符串中的字节数
);
TextOut 以坐标 X,Y为起点,
输出字节数为 nCount、
名为 lpstring中的字符串
12
5.3 文本操作实例
【 例 5-1】 在用户窗口上输出几行字符串,当窗口接收到
WM_PAINT消息后,显示的文本每次都被重新刷新。
#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(
HWND hWnd,
UINT iMessage,
UINT wParam,
LONG lParam
);
BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);
13
//主函数
int WINAPI WinMain(
HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG Message;
if(!InitWindowsClass(hInstance)) return FALSE;
if(!InitWindows(hInstance,nCmdShow))return FALSE;
while(GetMessage(&Message,0,0,0))//消息循环
{
TranslateMessage(&Message);
DispatchMessage(&Message);
}
return Message.wParam;
}
14
//消息处理函数
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
{
static long nXChar,nYChar;
HDC hDC; //定义指向设备上下文的句柄
short x;
TEXTMETRIC tm;
short LnCount=6;
PAINTSTRUCT PtStr; //定义指向包含绘图信息的结构体变量
static char *textbuf[]=
{
"This is the First line",
"This is the second line",
"This is the third line",
"This is the fourth line",
"This is the fifth line",
"This is the sixth line"
};
输出的文
本内容
15
switch(iMessage) //处理消息
{case WM_CREATE,//处理窗口创建消息
hDC=GetDC(hWnd) ; //获取当前设备表句柄
GetTextMetrics(hDC,&tm); //获取字体信息
nXChar=tm.tmAveCharWidth; //获取字符宽度
nYChar=tm.tmHeight+tm.tmExternalLeading;
ReleaseDC(hWnd,hDC); //释放当前设备句柄
return 0;
case WM_PAINT,//处理重画消息
hDC=BeginPaint(hWnd,&PtStr); //开始绘画
for(x=0;x<LnCount;x=x+1) //输出文本
TextOut(hDC,nXChar,nYChar*(1+x),textbuf[x],lstrlen(textbuf[x]));
EndPaint(hWnd,&PtStr);
return 0;
case WM_DESTROY,//结束应用程序
PostQuitMessage(0);
return 0;
default,//其他消息处理程序
return(DefWindowProc(hWnd,iMessage,wParam,lParam)) ;
}
}
16
BOOL InitWindowsClass(HINSTANCE hInstance) //初始化窗口类
{ WNDCLASS WndClass;
…………;
WndClass.style=CS_HREDRAW|CS_VREDRAW;
return RegisterClass(&WndClass);
}
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow) //初始化窗口
{ HWND hWnd;
hWnd=CreateWindow("WinText",//生成窗口
"文本显示示例程序 ",
WS_OVERLAPPEDWINDOW,
…….;
NULL);
if(!hWnd) return FALSE;
ShowWindow(hWnd,nCmdShow); //显示窗口
UpdateWindow(hWnd);
return TRUE;
}
17
【 例 5-2】 本程序通过在窗口中分五行分别显示五行
文本,以说明在窗口的用户区中输出文本的方法。
18
本例题的源代码如下:
#include <windows.h>
#include <string.h>
#include <stdlib.h>
#include <stdio.h>
LRESULT CALLBACK WndProc(HWND,UINT,WPARAM,LPARAM);
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInst,LPSTR lpszCmdLine,int nCmdShow)
{
HWND hwnd;
MSG Msg;
WNDCLASS wndclass;
char lpszClassName[] = "文本输出 ";
char lpszTitle[]= "EXAMPLE FOR THE TEXT OUTPUT";
wndclass.style = 0;
…………;
wndclass.lpszClassName = lpszClassName;
19
if( !RegisterClass( &wndclass))
{ MessageBeep(0);return FALSE; }
hwnd = CreateWindow
( lpszClassName,lpszTitle,
WS_OVERLAPPEDWINDOW,
CW_USEDEFAULT,CW_USEDEFAULT,
CW_USEDEFAULT,CW_USEDEFAULT,
NULL,NULL,hInstance,NULL);
ShowWindow( hwnd,nCmdShow);
UpdateWindow(hwnd);
while( GetMessage(&Msg,NULL,0,0))
{ TranslateMessage(&Msg); DispatchMessage(&Msg); }
return Msg.wParam;
}
20
LRESULT CALLBACK WndProc(HWND hwnd,UINT message,
WPARAM wParam,LPARAM lParam)
{
HDC hdc;
HFONT hF_black,hF_big; //定义两种字体句柄
PAINTSTRUCT ps;
TEXTMETRIC tm; //定义一个 TEXTMETRIC结构,用以记录字体信息
char lpsz_1[]=这是一行红色的、字体为 SYSTEM_FONT的文字,红色代表未来。 ";
char lpsz_2[]=现在显示的是自定义字体,颜色为绿色,绿色代表生机勃勃。 ";
char lpsz_3[]=现在展现在您面前的是蓝色的粗体字,蓝色代表广阔的海洋和天空。 ";
char lpsz_4[]="当前字体为大号、斜体并带有下划线的文字。 ";
char lpsz_5[]="现在您掌握了字体的操作了吗?";
char lpsz_6[]="祝您成功 !";
int X=0,Y=0;
SIZE size; //定义一个 SIZE类型的结构
21
switch(message){
case WM_PAINT:
hdc=BeginPaint(hwnd,&ps);
SetTextColor(hdc,RGB(255,0,0)); //设置文本颜色为红色
GetTextMetrics(hdc,&tm); //获取缺省字体,写入 tm结构中
TextOut(hdc,X,Y,lpsz_1,strlen(lpsz_1));//用当前字体输出文本
Y=Y+tm.tmHeight+100*tm.tmExternalLeading;
//计算换行时下一行文本的输出坐标
hF_black=CreateFont( //创建自定义字体
20,//字体的高度
0,//由系统根据高宽比选取字体最佳宽度值
0,//文本的倾斜度为 0,表示水平
0,//字体的倾斜度为 0
FW_HEAVY,//字体的粗度,FW_HEAVY为最粗
0,//非斜体字
0,//无下划线
0,//无删除线
ANSI_CHARSET,//表示所用的字符集为 ANSI_CHARSET
OUT_DEFAULT_PRECIS,//输出精度为缺省精度
CLIP_DEFAULT_PRECIS,//剪裁精度为缺省精度
DEFAULT_QUALITY,//输出质量为缺省值
DEFAULT_PITCH|FF_DONTCARE,//字间距和字体系列使用缺省值
"粗体字 " ); //字体名称
22
SetTextColor(hdc,RGB(0,255,0)); //设置文本颜色为绿色
SelectObject(hdc,hF_black); //将自定义字体选入设备环境
GetTextMetrics(hdc,&tm); //获取字体的信息,写入 tm结构中
TextOut(hdc,X,Y,lpsz_2,strlen(lpsz_2));//用当前字体输出文本
//换行继续输出文本,计算新行的起始 Y坐标位置
Y=Y+tm.tmHeight+10*tm.tmExternalLeading;
GetTextExtentPoint32(hdc,lpsz_2,strlen(lpsz_2),&size);
//获取字符串 /的宽度
SetTextColor(hdc,RGB(0,0,255)); //设置文本颜色为蓝色
TextOut(hdc,X,Y,lpsz_3,strlen(lpsz_3));//当前字体输出文本
Y=Y+tm.tmHeight+20*tm.tmExternalLeading;
23
hF_big=CreateFont //引入新字体
(
30,//字体高度
0,
0,
0,
FW_NORMAL,
1,//定义斜体
1,//定义输出时带下划线
0,
ANSI_CHARSET,//所使用的字符集
OUT_DEFAULT_PRECIS,
CLIP_DEFAULT_PRECIS,
DEFAULT_QUALITY,
DEFAULT_PITCH|FF_DONTCARE,
"大号字 "
);
24
SelectObject(hdc,hF_big);//将自定义字体选入设备环境
SetTextColor(hdc,RGB(155,155,155));//设置文本颜色
Y=Y+tm.tmHeight+20*tm.tmExternalLeading;
TextOut(hdc,X,Y,lpsz_4,strlen(lpsz_4));//输出文本
SetTextColor(hdc,RGB(255,0,0));//设置文本颜色为红色
Y=Y+tm.tmHeight+30*tm.tmExternalLeading;
TextOut(hdc,X,Y,lpsz_5,strlen(lpsz_5)); //输出文本
//在该行继续输出文本
GetTextExtentPoint32(hdc,lpsz_5,strlen(lpsz_5),&size);
//获取字符串的宽度
X=X+size.cx; //获取起始坐标
TextOut(hdc,X,Y,lpsz_6,strlen(lpsz_6)); //输出文本
EndPaint(hwnd,&ps);
break;
25
case WM_DESTROY:
DeleteObject(hF_black); //退出窗口时删除自定义字体
DeleteObject(hF_big);
PostQuitMessage(0);
break;
default:
return DefWindowProc(hwnd,message,wParam,lParam);
}
return 0;
}
26
【 5-3】 在窗口中显示出 26个英文字母,从左向右 字母依次位置提高
10个象素单位,并且颜色变为红色,然后回到正常位置;当到达最右
端后改变方向从右向左依次变成红色并位置提高 10个象素单位。在窗
口的第二行显示 26个字母,字体从正常到斜体,颜色从黑色到天蓝色
不断变换。如图所示。
用 nChar标志红
色跳起字母在
26个字母的位置
用 bRight,bLeft标志当前
移动方向,初始化
bRight=TRUE,bLeft=FALSE
27
本例题要解决 动态显示 问题,
首先处理第一行字符:在 WM_PAINT消息处理程序中,在得到了设
备环境句柄 hDC后,调用用户自定义的函数
CreateFont(hDC,nHeight,bItalic),第一个参数 hDC是设备环境
句柄,第 2个参数 nHeight是字体高度,第 3个参数 bItalic是斜字
体的标志变量
WM_CREATE
消息处理程序 定时器
调用 SetTimer(… )创建
WM_TIMER
消息处
理程序
调用 InvalidateRect(… )刷新
用户区 发送 WM_PAINT消息 实现动态
显示
28
下面这段程序按照黑色的字体输出从字符串开头到当前位置的字符串:
Y=tm.tmExternalLeading+10; //设置输出字符的 Y坐标
for(i=0;i<nChar;i++)
{SetTextColor(hDC,RGB(0,0,0)); //设置字体的颜色为黑色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X坐标
TextOut(hDC,X,Y,&lpsz_1[i],1);//输出从第 0个到第 nChar-1个字符
}
下面输出当前位置上的字符,当前位置的字符位置提高 10个象素单位,
字体颜色为红色:
SetTextColor(hDC,RGB(255,0,0));//设置字体的颜色为红色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X,Y坐标
Y=tm.tmExternalLeading; //提高 10个像素
hF = CreateFont(hDC,40,0); //创建字体
SelectObject(hDC,hF); //选入字体
TextOut(hDC,X,Y,&lpsz_1[nChar],1);//输出第 nChar个字符
Y=tm.tmExternalLeading+10;
for(i=nChar+1;i<nCharlen;i++)
{ SetTextColor(hDC,RGB(0,0,0)); //设置字体的颜色为黑色
X=X+tm.tmAveCharWidth*2; //设置输出字符的 X坐标
TextOut(hDC,X,Y,&lpsz_1[i],1); //输出后面的字符
}
29
下面设置 bRight和 bLeft的值。
if(nChar == nCharlen) //当输出到最后的一个字符时
{
bRight = FALSE; //改变红色字移动的方向为向左
bLeft = TRUE;
}
else(nChar == 0) //当输出到第一个字时
{
bRight = TRUE; //改变红色字移动的方向为向右
bLeft = FALSE;
}
if(bRight == TRUE) nChar++;
else nChar--;
如果 nChar==等于字符串长度 =〉 已到了字符串末尾,将 bRight置为 True
字符长度 ==0时,已到了最左端,将 bLeft置为 True;
当 bRight=True时字符位置标志 nChar加 1,当 bLeft=True时,字符位置标
志变量减 1。
30
下面输出第 2行字符:在 WM_PAINT处理程序中,加入下列代码:
hF = CreateFont(hDC,40,bItalic); //创建字体,大小为 40
SelectObject(hDC,hF); //选入字体
X = tm.tmAveCharWidth*2; //设置输出位置
Y = tm.tmHeight*2;
if(bItalic == TRUE)
SetTextColor(hDC,RGB(0,0,0));
else
SetTextColor(hDC,RGB(0,255,255));
TextOut(hDC,X,Y,lpsz_1,strlen(lpsz_1)); //输出
if(bItalic == TRUE)
bItalic=FALSE;
else
bItalic=TRUE;
调用用户自定义函数 CreateFont(… )创建斜体字,确定输出位置
根据 bItalic的状态设置字体的颜色。
当 bItalic为真时,输出斜体天蓝色字符;为假时,输出正常黑色字体
最后对 bItalic取反,在下一次显示与此次不同的另一种效果。
31
【 例 5-4】 将一首四句的古诗从右到左竖排输出。要求窗口每次接收
到 WM_PAINT消息时都刷新显示的文本。
32
#include<windows.h>
#include<stdlib.h>
#include<string.h>
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam);
BOOL InitWindowsClass(HINSTANCE hInstance);
BOOL InitWindows(HINSTANCE hInstance,int nCmdShow);
//主函数
int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrevInstance,
LPSTR lpCmdLine,int nCmdShow)
{
MSG Message;
if(!InitWindowsClass(hInstance)) return FALSE;
if(!InitWindows(hInstance,nCmdShow)) return FALSE;
while(GetMessage(&Message,0,0,0)) //消息循环
{TranslateMessage(&Message);
DispatchMessage(&Message); }
return Message.wParam;
}
33
long WINAPI WndProc(HWND hWnd,UINT iMessage,UINT wParam,LONG lParam)
1,{ static long nXChar,nCaps,nYChar;
2,int pointx,pointy,int i,j;
3,HDC hDC; //定义指向设备环境的句柄
4,TEXTMETRIC tm; //存放字体各种属性的结构体变量
5,PAINTSTRUCT PtStr; //指向包含绘图信息的结构体变量
6,static char *textbuf[4]={{"故人西辞黄鹤楼 "},{"烟花三月下扬州 "},
{"孤帆远影碧空尽 "},{"唯见长江天际流 "}};
7,switch(iMessage) //处理消息
8,{ case WM_CREATE,//处理窗口创建消息
9,hDC=GetDC(hWnd) ; //获取当前设备表句柄
10,GetTextMetrics(hDC,&tm); //获取字体信息
11,nXChar=tm.tmAveCharWidth; //获取字符宽度
12,nYChar=tm.tmHeight+tm.tmExternalLeading; //字符高度
13,nCaps=(tm.tmPitchAndFamily&1?3:2)*nXChar/2; //字间距
14,ReleaseDC(hWnd,hDC); return 0; //释放当前设备句柄
15,case WM_PAINT,//处理重画消息
16,hDC=BeginPaint(hWnd,&PtStr); //开始绘图
17,for(i=4;i>0;i--)
18,{for(j=0;j<7;j++) //输出文本
19,{ pointx=100+i*nXChar*5; pointy=50+j*(nYChar+nCaps);
20,TextOut(hDC,pointx,pointy,textbuf[4-i]+j*2,2); } }
21,EndPaint(hWnd,&PtStr); return 0; //结束绘图
22,case WM_DESTROY,//结束应用程序
PostQuitMessage(0); return 0;
23,default,return(DefWindowProc(hWnd,iMessage,wParam,lParam));}}
34
【 例 5-5】 创建自定义字体的例 题 程序 。在窗口中
显示, 自定义的字体,,字体颜色为红色,
背景色为蓝色。其运行结果应如下图所示:
35
LRESULT CALLBACK WndProc( HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
1,{HDC hdc ; //设备句柄
2,PAINTSTRUCT ps ; //画刷结构
3,int Xchar,Ychar;
4,SIZE size;
5,LPCTSTR *pstring=,自定义的字体, ;
6,RECT rect ; //无效矩形区
7,HFONT holdFont,hnewFont;
8,switch (message) //消息处理函数
9,{case WM_CREATE,return 0; //窗口创建
10,case WM_PAINT,//绘制消息
11,hnewFont=CreateFont //创建一种新的逻辑字体
12,( 64,0,0,0,500,0,0,0,
13,GB2312_CHARSET,
14,OUT_DEFAULT_PRECIS,
15,CLIP_DEFAULT_PRECIS,
16,DEFAULT_QUALITY,
17,DEFAULT_PITCH & FF_DONTCARE,
18.,黑体, );
36
19,hdc=BeginPaint (hwnd,&ps); //得到设备环境句柄
20,GetClientRect (hwnd,&rect); //得到需要绘制的客户区
21,holdFont=(HFONT)SelectObject(hdc,hnewFont); //选择新的字体
22,SetTextColor(hdc,RGB(255,0,0)); //设置文本颜色
23,SetBkColor(hdc,RGB(0,0,255)); //设置背景颜色
24,GetTextExtentPoint32(hdc,pstring,12,&size);
25,Xchar=(rect.right-rect.left)/2-size.cx/2;
26,Ychar=(rect.bottom-rect.top)/2-size.cy/2;
27,TextOut(hdc,Xchar,Ychar,pstring,12);
28,SelectObject(hdc,holdFont); //保存原来的字体格式
29,DeleteObject(hnewFont); //删除新的字体格式
30,EndPaint (hwnd,&ps) ; //结束绘制
return 0 ;
case WM_DESTROY,//退出消息
PostQuitMessage (0) ; return 0 ;
}
return DefWindowProc(hwnd,message,wParam,lParam) ;
}