转自:http://www.jizhuomi.com/software/241.html

上一节讲了CFont字体类,本节主要讲解文本输出的方法和实例。

文本输出过程

在文本输出到设备以前,我们需要确定字体、字体颜色和输出的文本内容等信息。Windows窗口的客户区由应用程序管理,所以我们还要在应用程序中控制输出文本的格式,例如后续字符的位置、换行等格式。

由此,文本的输出过程大致包括确定字体信息、格式化文本和执行输出操作三个步骤。下面分别讲解。

1、确定字体信息

文本在输出以前应该先确定字体信息,或者是当前正在使用的字体,或者是自定义的字体,之后就可以根据确定的字体来显示文本或者利用字体信息来设定文本的格式了,例如,我们可以根据当前字体的字符高度来确定下一行字符在什么位置输出。

自定义字体可以通过CFont类的创建字体的几个成员函数完成。获取当前选择字体的信息可以使用API函数GetTextMetrics实现,此函数的原型如下:

BOOL GetTextMetrics(__in   HDC hdc,__out  LPTEXTMETRIC lptm);

参数hdc为设备上下文的句柄;参数lptm是指向TEXTMETRIC结构体变量的指针,此结构体变量用于接收字体信息。TEXTMETRIC结构体的定义如下:

C++代码:
typedef struct tagTEXTMETRIC {
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轴尺寸
TCHAR tmFirstChar; // 字体中第一个字符值
TCHAR tmLastChar; // 字体中最后一个字符值
TCHAR tmDefaultChar; // 替换字体中没有的字符
TCHAR tmBreakChar; // 作为分隔符的字符
BYTE tmItalic; // 非0则表示字体为斜体
BYTE tmUnderlined; // 非0则表示字体有下划线
BYTE tmStruckOut; // 非0则表示字符带有删除线
BYTE tmPitchAndFamily;// 字体间距和字体族
BYTE tmCharSet; // 字符集
} TEXTMETRIC, *PTEXTMETRIC;
 

 2、格式化文本

格式化文本一般包括两种,一种是确定文本行中后续文本的位置,另一种是确定换行时下一行文本的位置。

确定后续文本的位置

一般我们可以先获取当前字符串的宽度,根据此宽度确定文本行中后续文本的位置。当前字符串的宽度可以通过API函数GetTextExtentPoint32获得。GetTextExtentPoint32函数的原型如下:

BOOL GetTextExtentPoint32(__in   HDC hdc,__in   LPCTSTR lpString,__in   int c,__out  LPSIZE lpSize);

参数hdc为设备上下文的句柄;参数lpString为指向文本字符串缓存的指针,此字符串不是必须以结束符结尾的,因为参数c指定了长度;参数c为lpString指向的字符串的长度;参数lpSize为指向SIZE结构体变量的指针,此SIZE结构体变量用于接收字符串的宽度和高度信息。SIZE结构体定义如下:

C++代码
typedef struct tagSIZE
{
LONG cx; // 宽度
LONG cy; // 高度
} SIZE, *PSIZE;

已知本字符串的起始水平坐标和宽度,两者相加即是后续文本的起始坐标。

确定换行时下一行文本的位置

由GetTextMetrics函数获取了当前字体的信息并存入TEXTMETRIC结构体后,通过计算当前文本行的垂直坐标、当前字体的高度和行间距之和,就可以得到换行时下一行的垂直坐标。

3、执行文本输出操作

最后,通过API函数TextOut执行文本输出操作。TextOut函数的原型如下:

BOOL TextOut(__in  HDC hdc,__in  int nXStart,__in  int nYStart,__in  LPCTSTR lpString,__in  int cbString);

参数hdc为设备上下文的句柄;参数nXStart为起始点x坐标;参数nYStart为起始点y坐标;参数lpString为要输出的文本字符串;参数cbString为字符串中要输出的字符的数量。

当然也可以使用设备上下文类CDC的成员函数TextOut来输出,CDC::TextOut函数的两种重载形式如下:

virtual BOOL TextOut(int x,int y,LPCTSTR lpszString,int nCount);
       BOOL TextOut(int x,int y,const CString& str);

参数x指定文本起始点的x坐标;参数y指定文本起始点的y坐标;参数lpszString为要输出的文本字符串;参数nCount指定字符串中的字节个数;参数str为包含要输出的字符的CString对象。

字体和文本输出的应用实例

下面给大家演示一个简单的关于字体和文本输出的实例。功能就是实现两个字符串分别在水平方向和垂直方向上定时滚动。实现步骤如下:

1、创建一个基于对话框的MFC工程,名字设置为“Example48”。

2、在自动生成的对话框模板IDD_EXAMPLE48_DIALOG中,删除“TODO: Place dialog controls here.”静态文本框

3、在Example48Dlg.h文件中为CExample48类添加成员变量:

C++代码
int m_nTextX;   // 水平滚动文本的起始点的x坐标
int m_nTextY; // 垂直滚动文本的起始点的y坐标
CFont m_newFont; // 新字体
CFont *m_pOldFont; // 选择新字体之前的字体

4、在CExample48Dlg类的构造函数中,初始化新添加的成员变量:

C++代码
CExample48Dlg::CExample48Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(CExample48Dlg::IDD, pParent)
{
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); m_nTextX = ;
m_nTextY = ;
m_pOldFont = NULL;
}

5、在CExample48Dlg对话框初始化函数中,创建新的字体,并开启定时器

C++代码
BOOL CExample48Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog(); // Add "About..." menu item to system menu. // IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000); CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
} // Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon // TODO: Add extra initialization here
// 创建一种新的字体(18点,隶书)
m_newFont.CreatePointFont(, _T("隶书")); // 设置定时器,定时时间为200ms
SetTimer(,,NULL); return TRUE; // return TRUE unless you set the focus to a control
}
 

6、修改CExample48Dlg::OnPaint()函数,如果窗口没有最小化就在指定的位置输出文本,即在OnPaint函数中if(IsIconic())对应的else大括号内添加相应代码。CExample48Dlg::OnPaint()函数修改如下:

C++代码
void CExample48Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(dc.GetSafeHdc()), ); // Center icon in client rectangle
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(&rect);
int x = (rect.Width() - cxIcon + ) / ;
int y = (rect.Height() - cyIcon + ) / ; // Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CPaintDC dc(this); // device context for painting
// 设置m_newFont对象的字体为当前字体,并将之前的字体指针保存到m_pOldFont
m_pOldFont = (CFont*)dc.SelectObject(&m_newFont);
// 设置
dc.SetBkMode(TRANSPARENT); //设置背景为透明!
// 设置文本颜色为红色
dc.SetTextColor(RGB(,,));
// 在指定位置输出文本
dc.TextOut(m_nTextX,,_T("欢迎来到鸡啄米!"));
// 设置文本颜色为绿色
dc.SetTextColor(RGB(,,));
// 在指定位置输出文本
dc.TextOut(,m_nTextY,_T("谢谢关注www.jizhuomi.com"));
// 恢复以前的字体
dc.SelectObject(m_pOldFont); CDialogEx::OnPaint();
}
}
 

7、在Class View类视图中找到CExample48Dlg,右键点Properties,显示出其属性页,在属性页工具栏上点击Messages按钮,找到WM_TIMER消息,添加消息响应函数CExample48Dlg::OnTimer(UINT_PTR nIDEvent),并在此函数中修改两个文本输出的坐标位置。

C++代码
void CExample48Dlg::OnTimer(UINT_PTR nIDEvent)
{
// TODO: Add your message handler code here and/or call default
LOGFONT logFont;
// 获取m_newFont字体的LOGFONT结构
m_newFont.GetLogFont(&logFont); // 将m_nTextX的值减5
m_nTextX -= ;
// 如果m_nTextX小于10,则文本“欢迎来到鸡啄米”回到起始位置
if (m_nTextX < )
m_nTextX = ; // 将m_nTextY的值加一个字符高度
m_nTextY += abs(logFont.lfHeight);
// 如果m_nTextY大于260,则文本“谢谢关注www.jizhuomi.com”回到起始位置
if (m_nTextY >)
m_nTextY = ; // 使窗口客户区无效,之后就会重绘
Invalidate(); CDialogEx::OnTimer(nIDEvent);
}

到这一步,两个文本就可以分别在水平和垂直方向滚动了。简单解释下这个过程:程序刚启动时,会调用OnPaint函数,在初始位置绘出两个文本,然后每次到了定时器的定时时间后,会执行OnTimer函数,修改两个文本的坐标值,并通过Invalidate使窗口重绘,又会重新调用OnPaint函数绘制两个文本。这样通过定时修改坐标值就实现了两个文本的滚动效果。

8、运行程序,最终的效果如下图:

好了,本节就讲到这里了,最后的实例大家可以自己丰富下它的功能,看看效果。

VS2010-MFC(字体和文本输出:文本输出)的更多相关文章

  1. VS2010/MFC字体和文本输出:文本输出

    字体和文本输出:文本输出 本节主要讲解文本输出的方法和实例. 文本输出过程 在文本输出到设备以前,我们需要确定字体.字体颜色和输出的文本内容等信息.Windows窗口的客户区由应用程序管理,所以我们还 ...

  2. VS2010/MFC编程入门之四十七(字体和文本输出:CFont字体类)

    上一节中鸡啄米讲了MFC异常处理,本节的主要内容是字体CFont类. 字体简介 GDI(Graphics Device Interface),图形设备接口,是Windows提供的一些函数和结构,用于在 ...

  3. VS2010/MFC编程入门之四十八(字体和文本输出:文本输出)

    鸡啄米在上一节中讲了CFont字体类,本节主要讲解文本输出的方法和实例. 文本输出过程 在文本输出到设备以前,我们需要确定字体.字体颜色和输出的文本内容等信息.Windows窗口的客户区由应用程序管理 ...

  4. MFC字体与文本输出

    字体 成员函数 1.CFont( ); 构造一个CFont对象.此对象在使用之前应该先使用CreateFont.CreateFontIndirect.CreatePointFont或CreatePoi ...

  5. 【MFC】MFC改变对话框中静态文本的字体大小

    MFC改变对话框中静态文本的字体大小 2010/08/09 11:30 VC的对话框字体设置对所有控件都有效,你不能单独地改变某个静态文本的字体.对于你的问题,需要首先用CreateFont来建立一个 ...

  6. 在MVC视图的代码块中,直接输出文本,有几种方式?

    @{ <div>我爱IT,我是程序员,我骄傲---</div> <!--在C#代码块中,输出文本--> <!--1.0 使用Razor内置标签text--&g ...

  7. 调试location指令时,直接让location输出文本

    有时候我们调试location指令时希望location指令能够直接输出文本,这样能够方便我们进行调试.这时我们可以使用echo模块实现,但是大多数情况我们没有安装这个模块,那么我们还可以使用另一个方 ...

  8. php GD 和图像处理函数, 用 STHUPO.TTF 字体向图像写入文本

    php GD 和图像处理函数,   用  STHUPO.TTF 字体向图像写入文本 注意: 01)   imagettftext() 这个函数不能使用相对路径, 要想使用相对路径要先使用  puten ...

  9. VS2010/MFC编程入门教程之目录和总结

    鸡啄米的这套VS2010/MFC编程入门教程到此就全部完成了,虽然有些内容还未涉及到,但帮助大家进行VS2010/MFC的入门学习业已足够.以此教程的知识为基础,学习VS2010/MFC较为深入的内容 ...

  10. VS2010/MFC编程入门之四十九(图形图像:CDC类及其屏幕绘图函数)

    上一节中鸡啄米讲了文本输出的知识,本节的主要内容是CDC类及其屏幕绘图函数. CDC类简介 CDC类是一个设备上下文类. CDC类提供了用来处理显示器或打印机等设备上下文的成员函数,还有处理与窗口客户 ...

随机推荐

  1. python_django_在views模块中操作状态保持(session)

    什么叫状态保持? 就比如说我们登陆一个网站,登陆之后的当前页面显示的是登陆状态,但是我们要再跳转同一网站的其他页面,则显示的未登录状态,状态保持就是:我们在当前页面登陆后,再访问其他页面时也显示为登陆 ...

  2. 了解linux web的监听工具

    zabbix cacti Nagios 本想安装的,但是安装需要一个 空的服务器,因为服务器已经有安装 LAMP,故没有去了解 尝试了 cacti ,因为本地环境版本问题,只能使用0.8.8a版本,并 ...

  3. DOM——节点操作

    节点操作  var body = document.body; var div = document.createElement('div'); body.appendChild(div); ​ va ...

  4. JQuery简单实用的模板引擎

    1.在html界面声明模板(注意type类型) <script id="tmplInvokeProvider" type="text/x-jquery-tmpl&q ...

  5. hadoop的基准测试

    hadoop的基准测试 实际生产环境当中,hadoop的环境搭建完成之后,第一件事情就是进行压力测试,测试我们的集群的读取和写入速度,测试我们的网络带宽是否足够等一些基准测试 测试写入速度 向HDFS ...

  6. hdu多校第九场 1002 (hdu6681) Rikka with Cake 树状数组维护区间和/离散化

    题意: 在一块长方形蛋糕上切若干刀,每一刀都是从长方形某条边开始,垂直于这条边,但不切到对边,求把长方形切成了多少块. 题解: 块数=交点数+1 因为对于每个交点,唯一且不重复地对应着一块蛋糕. 就是 ...

  7. STM32F103

    memory map • Four masters: – Cortex® -M3 core DCode bus (D-bus) and System bus (S-bus)– GP-DMA1 & ...

  8. python list基本操作一

    a = [1,2,3,1,2,3] 一.删除元素 1.按索引删除: a.pop(1) # 删除第二个值 # in:[1,2,3,2] # out:[1,3,2] 返回值:被删除的元素,这个时候list ...

  9. Scala 学习2

    去map里面的数据 scala> val map = Map("a"->1, "b"->2, "c"->3) map ...

  10. jQuery Ajax请求 .net 一般处理程序

    初学ajax 一个简单的功能,调试了2个小时,代码如下虽然成功了 但是有错误 <!DOCTYPE html> <html> <head> <meta http ...