???????鸡皇冠现金官网hg6388|首页在上一节中讲了CFont字体类,本节主要讲解文本输出的方法和实例。

?????? 文本输出过程

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

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

?????? 1、确定字体信息

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

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

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

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

C++代码
  1. typedef?struct?tagTEXTMETRIC?{ ??
  2. ??LONG??tmHeight;????????//?字符高度 ??
  3. ??LONG??tmAscent;????????//?字符基线以上的高度 ??
  4. ??LONG??tmDescent;???????//?字符基线以下的高度 ??
  5. ??LONG??tmInternalLeading;?//?由tmHeight成员指定的字符高度顶部的空间 ??
  6. ??LONG??tmExternalLeading;?//?行间距 ??
  7. ??LONG??tmAveCharWidth;??//?字符的平均宽度 ??
  8. ??LONG??tmMaxCharWidth;??//?字符的最大宽度 ??
  9. ??LONG??tmWeight;????????//?字符的粗度 ??
  10. ??LONG??tmOverhang;??????//?合成字体间附加的宽度 ??
  11. ??LONG??tmDigitizedAspectX;?//?为输出设备设计的x轴尺寸 ??
  12. ??LONG??tmDigitizedAspectY;?//?为输出设备设计的y轴尺寸 ??
  13. ??TCHAR?tmFirstChar;?????//?字体中第一个字符值 ??
  14. ??TCHAR?tmLastChar;??????//?字体中最后一个字符值 ??
  15. ??TCHAR?tmDefaultChar;???//?替换字体中没有的字符 ??
  16. ??TCHAR?tmBreakChar;?????//?作为分隔符的字符 ??
  17. ??BYTE??tmItalic;????????//?非0则表示字体为斜体 ??
  18. ??BYTE??tmUnderlined;????//?非0则表示字体有下划线 ??
  19. ??BYTE??tmStruckOut;?????//?非0则表示字符带有删除线 ??
  20. ??BYTE??tmPitchAndFamily;//?字体间距和字体族 ??
  21. ??BYTE??tmCharSet;???????//?字符集 ??
  22. }?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++代码
  1. typedef?struct?tagSIZE?{ ??
  2. ??LONG?cx;???//?宽度 ??
  3. ??LONG?cy;???//?高度 ??
  4. }?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对象。

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

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

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

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

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

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

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

C++代码
  1. CExample48Dlg::CExample48Dlg(CWnd*?pParent?/*=NULL*/) ??
  2. ????:?CDialogEx(CExample48Dlg::IDD,?pParent) ??
  3. { ??
  4. ????m_hIcon?=?AfxGetApp()->LoadIcon(IDR_MAINFRAME); ??
  5. ??
  6. ????m_nTextX?=?260; ??
  7. ????m_nTextY?=?10; ??
  8. ????m_pOldFont?=?NULL; ??
  9. }??

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

C++代码
  1. BOOL?CExample48Dlg::OnInitDialog() ??
  2. { ??
  3. ????CDialogEx::OnInitDialog(); ??
  4. ??
  5. ????//?Add?"About..."?menu?item?to?system?menu. ??
  6. ??
  7. ????//?IDM_ABOUTBOX?must?be?in?the?system?command?range. ??
  8. ????ASSERT((IDM_ABOUTBOX?&?0xFFF0)?==?IDM_ABOUTBOX); ??
  9. ????ASSERT(IDM_ABOUTBOX?
  10. ??
  11. ????CMenu*?pSysMenu?=?GetSystemMenu(FALSE); ??
  12. ????if?(pSysMenu?!=?NULL) ??
  13. ????{ ??
  14. ????????BOOL?bNameValid; ??
  15. ????????CString?strAboutMenu; ??
  16. ????????bNameValid?=?strAboutMenu.LoadString(IDS_ABOUTBOX); ??
  17. ????????ASSERT(bNameValid); ??
  18. ????????if?(!strAboutMenu.IsEmpty()) ??
  19. ????????{ ??
  20. ????????????pSysMenu->AppendMenu(MF_SEPARATOR); ??
  21. ????????????pSysMenu->AppendMenu(MF_STRING,?IDM_ABOUTBOX,?strAboutMenu); ??
  22. ????????} ??
  23. ????} ??
  24. ??
  25. ????//?Set?the?icon?for?this?dialog.??The?framework?does?this?automatically ??
  26. ????//??when?the?application's?main?window?is?not?a?dialog ??
  27. ????SetIcon(m_hIcon,?TRUE);?????????//?Set?big?icon ??
  28. ????SetIcon(m_hIcon,?FALSE);????????//?Set?small?icon ??
  29. ??
  30. ????//?TODO:?Add?extra?initialization?here ??
  31. ????//?创建一种新的字体(18点,隶书) ??
  32. ????m_newFont.CreatePointFont(180,?_T("隶书")); ??
  33. ??
  34. ????//?设置定时器,定时时间为200ms ??
  35. ????SetTimer(1,200,NULL); ??
  36. ??
  37. ????return?TRUE;??//?return?TRUE??unless?you?set?the?focus?to?a?control ??
  38. }??

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

C++代码
  1. void?CExample48Dlg::OnPaint() ??
  2. { ??
  3. ????if?(IsIconic()) ??
  4. ????{ ??
  5. ????????CPaintDC?dc(this);?//?device?context?for?painting ??
  6. ??
  7. ????????SendMessage(WM_ICONERASEBKGND,?reinterpret_cast<WPARAM>(dc.GetSafeHdc()),?0); ??
  8. ??
  9. ????????//?Center?icon?in?client?rectangle ??
  10. ????????int?cxIcon?=?GetSystemMetrics(SM_CXICON); ??
  11. ????????int?cyIcon?=?GetSystemMetrics(SM_CYICON); ??
  12. ????????CRect?rect; ??
  13. ????????GetClientRect(&rect); ??
  14. ????????int?x?=?(rect.Width()?-?cxIcon?+?1)?/?2; ??
  15. ????????int?y?=?(rect.Height()?-?cyIcon?+?1)?/?2; ??
  16. ??
  17. ????????//?Draw?the?icon ??
  18. ????????dc.DrawIcon(x,?y,?m_hIcon); ??
  19. ????} ??
  20. ????else??
  21. ????{ ??
  22. ????????CPaintDC?dc(this);?//?device?context?for?painting ??
  23. ????????//?设置m_newFont对象的字体为当前字体,并将之前的字体指针保存到m_pOldFont ??
  24. ????????m_pOldFont?=?(CFont*)dc.SelectObject(&m_newFont); ??
  25. ????????//?设置 ??
  26. ????????dc.SetBkMode(TRANSPARENT);?//设置背景为透明! ??
  27. ????????//?设置文本颜色为红色 ??
  28. ????????dc.SetTextColor(RGB(255,0,0)); ??
  29. ????????//?在指定位置输出文本 ??
  30. ????????dc.TextOut(m_nTextX,10,_T("欢迎来到鸡皇冠现金官网hg6388|首页!")); ??
  31. ????????//?设置文本颜色为绿色 ??
  32. ????????dc.SetTextColor(RGB(0,255,0)); ??
  33. ????????//?在指定位置输出文本 ??
  34. ????????dc.TextOut(10,m_nTextY,_T("谢谢关注www.jizhuomi.com")); ??
  35. ????????//?恢复以前的字体 ??
  36. ????????dc.SelectObject(m_pOldFont); ??
  37. ??
  38. ????????CDialogEx::OnPaint(); ??
  39. ????} ??
  40. }??

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

C++代码
  1. void?CExample48Dlg::OnTimer(UINT_PTR?nIDEvent) ??
  2. { ??
  3. ????//?TODO:?Add?your?message?handler?code?here?and/or?call?default ??
  4. ????LOGFONT?logFont; ??
  5. ????//?获取m_newFont字体的LOGFONT结构 ??
  6. ????m_newFont.GetLogFont(&logFont); ??
  7. ??
  8. ????//?将m_nTextX的值减5 ??
  9. ????m_nTextX?-=?5; ??
  10. ????//?如果m_nTextX小于10,则文本“欢迎来到鸡皇冠现金官网hg6388|首页”回到起始位置 ??
  11. ????if?(m_nTextX?
  12. ????????m_nTextX?=?260; ??
  13. ??
  14. ????//?将m_nTextY的值加一个字符高度 ??
  15. ????m_nTextY?+=?abs(logFont.lfHeight); ??
  16. ????//?如果m_nTextY大于260,则文本“谢谢关注www.jizhuomi.com”回到起始位置 ??
  17. ????if?(m_nTextY?>260) ??
  18. ????????m_nTextY?=?10; ??
  19. ??
  20. ????//?使窗口客户区无效,之后就会重绘 ??
  21. ????Invalidate(); ??
  22. ??
  23. ????CDialogEx::OnTimer(nIDEvent); ??
  24. }??

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

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

VS2010/MFC字体和文本输出实例

?????? 好了,本节就讲到这里了,最后的实例大家可以自己丰富下它的功能,看看效果。鸡皇冠现金官网hg6388|首页谢谢大家的支持。

除非特别注明,鸡皇冠现金官网hg6388|首页文章均为原创
转载请标明本文地址:http://www.jizhuomi.com/software/241.html
2012年9月22日
作者:鸡皇冠现金官网hg6388|首页 分类:软件开发 浏览: 评论:8