🔳🔳 绘制线条 、画刷绘图、绘制连续线条、绘制扇形效果的线条
🔳🔳 插入符【文本插入符|图形插入符】、窗口重绘、路径、字符输入【设置字体|字幕变色】
🔳🔳 菜单命令响应函数、菜单命令的路由、基本菜单操作、动态菜单操作、电话本实例
🔳🔳 对话框的创建与显示、动态创建按钮、控件的访问【控件调整|静态文本控件|编辑框控件】、对话框伸缩功能、输入焦点的传递、默认按钮的说明
🔳🔳修改应用程序窗口的外观【窗口光标|图标|背景】、模拟动画图标、工具栏编程、状态栏编程、进度栏编程、在状态栏上显示鼠标当前位置、启动画面
🔳🔳设置对话框、颜色对话框、字体对话框、示例对话框、改变对话框和控件的背景及文本颜色、位图显示
一、插入符
1. 创建文本插入符
创建插入符,可以利用CWnd类的createSolidCaret)函数完成。
该函数原型声明一下:
void CreateSolidCaret(int nWidth,int nHeight)
- nWidth: 指定输入符号的宽度。如果该参数的值为0,那么系统将其设置为系统定义的窗口边界的宽度。
- nHeight:指定插入符的高度。若该参数的值为0,那么系统将其设置为系统定义的窗口边界的高度。
单文档类型的工程有两个窗口,即框架类窗口和视类窗口。视类窗口永远位于框架类窗口之上。对窗口客户区的鼠标和键盘操作实际上都是在视类窗口上进行的,因此应该在视类窗口上创建插入符。
插入符的创建应该在窗口创建之后进行的,可以在WM_CREATE消息的响应函数OnCreate中添加创建插入符的代码。
1)添加消息响应函数OnCreate函数
2)创建一个宽度为20、高度为100的插入符。并用ShowCaret
3) 让插入符适合于当前字体的大小:
得到当前设备描述表中字体的信息,也就是文本的信息,也就是文本的信息,然后根据字体的信息来调整插入符的大小。
调用CDC类的GetTextMetrics成员函数可以得到设备描述表中当前字体的度量信息。该函数的原型声明如下所示:
BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const;
参数需要一个TEXTMETRIC结构体的指针,通过GetTextMetrics函数的调用,它会用设备描述表中当前字体的信息来填充这个结构体。
typedef struct tagTEXTMETRICW
{
LONG tmHeight;
LONG tmAscent;
LONG tmDescent;
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth;
LONG tmMaxCharWidth;
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
WCHAR tmFirstChar;
WCHAR tmLastChar;
WCHAR tmDefaultChar;
WCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRICW, *PTEXTMETRICW, NEAR *NPTEXTMETRICW, FAR *LPTEXTMETRICW;
从图中看到,对英文字母来说,g和h的高度明显不同,每一种字体都有一条基线,基线以上到图中h字符最高点之间的高度称为升序高度tmAscent,基线以下到图中g字符最低点之间的高度称为降序高度tmDescent。升序高度和降序高度之和就是字体的高度tmHeight。字符并没有一个具体的宽度值,只有一个平均宽度tmAveCharWidth。最大字符宽度tmMaxCharWidth。
得到字体的信息,就可以利用字体的高度和平均宽度来计算插入符的高度和宽度。
int CMFCTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
//创建设备描述表
CClientDC dc(this);
//定义文本信息结构体变量
TEXTMETRIC tm;
//获得设备描述表中的文本信息
dc.GetTextMetrics(&tm);
//根据字体大小,创建合适的插入符
CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight);
ShowCaret();
return 0;
}
应用程序窗口的左上角出现一条闪烁的竖线,且大小比较符合常规。
2. 创建图形插入符
利用CWnd类的另一个函数CreateCRect创建图形插入符,原型:
void CreateCare(CBitmap* pBitmap);
函数需要一个CBitmap类型的指针,利用CBitmap成员函数初始化位图对象,才能使用此对象。
添加位图对象:
与资源相关联的对象,在其析构时候都会把与之相关联的资源销毁。所以CBitmap应该设置为该视类的成员变量。
int CMFCTestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
//============图像插入符=================
CClientDC dc(this);
bitmap.LoadBitmap(IDB_BITMAP4);
CreateCaret(&bitmap);
ShowCaret();
return 0;
}
二、窗口重绘
Windows程序运行时,若程序的窗口发生变化,窗口会发生重绘,窗口中已输入的文字或者图像会被擦除。若想继续将内容保留到窗口上,就要响应WM_PAINT消息响应函数的OnDraw函数,当窗口发生重绘时,程序框架代码就会重新调用该函数。
2.1 OnDraw函数
当OnDraw函数被调用时,应用程序框架会构造一个CDC类对象的指针并传播给这个函数,函数内部就不需要再去构造CDC类的对象,可以直接使用传递进来的CDC对象指针去调用CDC类的成员函数,完成绘图功能。
- C语言中,定义一个char*类型的变量。MFC中,提供了一个字符串类:CString。
- 一个CString对象由一串可变长度的字符组成。
- CString重载了很多操作符,例如:赋值“=”、相加“+”操作符。
-
CString的构造函数
Cstring(); CString( const CString& stringSrc); CString(TCHAR ch,int nRepeat=1); CString(LPCTSTR lpch,int nLength); CString(const unsigned char* psz);
屏幕中打印出字符串:
void CMFCTestView::OnDraw(CDC* pDC) { CMFCTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 CString str("静待花开"); //CString str; //str="静待花开" pDC->TextOut(100, 150, str); }
2.2 添加字符串资源
CString类还提供了一个成员函数:LoadString,其声明形式如下:
BOOL LoadString(UINT nID);
可以构造一个由nID标识的字符串资源,在需要使用时将其转载到字符串变量上。
-
如何定义字符串资源?
Resource View选项卡,其中有一项是String Table,表示字符串表。用鼠标双击该项,VC++将在右边的窗格上为我们打开当前程序的字符串表,其中列出了已经定义的各个字符串。表格中,第一列是字符串ID,第三列是字符串资源的文本内容。
添加新的字符串资源,在字符串表底部空行上单击。添加一个字符串,ID会自动生成,字符串内容自己编辑。如下:void CMFCTestView::OnDraw(CDC* pDC) { CMFCTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 CString str("静待花开"); pDC->TextOut(100, 150, str); CString str2; str2 = "O(∩_∩)O哈哈~哈哈哈hahhah"; pDC->TextOutW(300,150,str2); str.LoadString(IDS_STRING101); pDC->TextOutW(50, 200, str); }
三、路径
设备描述表中有一个路径层。MFC中,创建路径层利用CDC类提供的两个函数实现。
- 1.BeginPath:在设备描述表中打开一个路径层
- 2.利用图形设备接口GDI提供的绘图函数进行绘图操作,例如绘制点,矩形,椭圆等。
- 3.EndPath:绘图完成后,通过此函数关闭这个路径层。
CDC类为我们提供了GetTextExtent函数,利用这个函数可以获得一个字符串在屏幕上显示的宽度的高度,这个函数的一种声明形式如下:
CSize GetTextExtent(const CString str) const;
我们需要给这个函数传递一个字符串,它会返回一个CSize类型的对象。
CSize类定义如下:
typedef struct tagSIZE{
int cx;//宽度
int cy;//高度
}SIZE;
若要得到字符串在窗口中的显示宽度,必须针对特定的字符串调用GetTextExtent函数。
- GetTextExtent函数获取某个特定的字符串在窗口中显示时所占据的宽度与高度。
- GetTextMetrics函数获得的是设备描述表中当前字体的度量信息。
void CMFCTestView::OnDraw(CDC* pDC)
{
CMFCTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CString str;
str="静待花开";
pDC->TextOut(50, 50, str);
CSize sz = pDC->GetTextExtent(str);
str.LoadString(IDS_STRING101);
pDC->TextOut(0, 200, str);
pDC->BeginPath();
pDC->Rectangle(50,50, 50+sz.cx+50, 50+sz.cy+50);
pDC->EndPath();
}
探究路径线的作用:
void CMFCTestView::OnDraw(CDC* pDC)
{
CMFCTestDoc* pDoc = GetDocument();
ASSERT_VALID(pDoc);
if (!pDoc)
return;
// TODO: 在此处为本机数据添加绘制代码
CString str;
str="静待花开";
pDC->TextOut(50, 50, str);
CSize sz = pDC->GetTextExtent(str);
str.LoadString(IDS_STRING101);
pDC->TextOut(0, 200, str);
pDC->BeginPath();
pDC->Rectangle(50,50, 50+sz.cx+50, 50+sz.cy+50);
pDC->EndPath();
for (int i = 0; i < 300; i+=30)
{
pDC->MoveTo(0, i);
pDC->LineTo(300, i);
pDC->MoveTo(i, 0);
pDC->LineTo(i, 300);
}
}
CDC类提供了一个SelectClipPath函数,该函数的作用:把当前设置的路径层和设备描述表中已有的裁剪区域按照一种指定的模式进行一个互操作。该函数声明形式如下:
BOOL SelectClipPath(int nMode);
参数nMode用于指示互操作的模式。
-
RGN_BIFF:新的裁剪区域包含当前裁剪区域,但排除当前路径层区域。
void CMFCTestView::OnDraw(CDC* pDC) { CMFCTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 CString str; str="静待花开"; pDC->TextOut(50, 50, str); CSize sz = pDC->GetTextExtent(str); str.LoadString(IDS_STRING101); pDC->TextOut(0, 200, str); pDC->BeginPath(); pDC->Rectangle(50,50, 50+sz.cx, 50+sz.cy); pDC->EndPath(); pDC->SelectClipPath(RGN_DIFF); for (int i = 0; i < 300; i+=30) { pDC->MoveTo(0, i); pDC->LineTo(300, i); pDC->MoveTo(i, 0); pDC->LineTo(i, 300); } }
窗口中绘制的线条到了程序设置的矩形路径部分就断开了。
-
RGN_AND:新的裁剪区域是当前裁剪区域是当前裁剪区域和当前路径层的交集。
void CMFCTestView::OnDraw(CDC* pDC) { CMFCTestDoc* pDoc = GetDocument(); ASSERT_VALID(pDoc); if (!pDoc) return; // TODO: 在此处为本机数据添加绘制代码 CString str; str="静待花开"; pDC->TextOut(50, 50, str); CSize sz = pDC->GetTextExtent(str); str.LoadString(IDS_STRING101); pDC->TextOut(0, 200, str); pDC->BeginPath(); pDC->Rectangle(50,50, 50+sz.cx, 50+sz.cy); pDC->EndPath(); pDC->SelectClipPath(RGN_AND); for (int i = 0; i < 300; i+=30) { pDC->MoveTo(0, i); pDC->LineTo(300, i); pDC->MoveTo(i, 0); pDC->LineTo(i, 300); } }
只有矩形中显示线条,其他部分就没有线条。
四、字符输入
实现字符的输入功能,当用户在键盘上按下某个字符按键后,该字符输出到程序窗口上。
1)首先让视图类捕获WM_CHAR消息
2)定义一个成员变量CString类型的成员变量:m_strLine,用门用于存放输入的字符串,并在视类的构造函数中初始化此变量。
3)程序应该在当前插入符的位置输出字符,需要捕获鼠标左键按下消息WM_LBUTTONDOWN,在该消息响应函数中,把插入符移动到鼠标左键单击出,利用CWnd类的SetCaretPos函数实现。声明如下:
static void PASCAL SetCaretPos(POINT point)
插入符移动到鼠标左键单击处的位置。
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
// 插入符移动到鼠标左键单击处的位置
SetCaretPos(point);
CView::OnLButtonDown(nFlags, point);
}
鼠标左键单击任何窗口的位置,插入符会随之移动。
4)m_strLine取值变化:
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
// 插入符移动到鼠标左键单击处的位置
SetCaretPos(point);
m_strLine.Empty();
CView::OnLButtonDown(nFlags, point);
}
5)增加一个CPoint类型的成员变量保存鼠标左键单击处的坐标,以便在点击处输入新字符。变量取名m_ptOrigin。构造函数中初始化为0。
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
// 插入符移动到鼠标左键单击处的位置
SetCaretPos(point);
m_strLine.Empty();
m_ptOrigin = point;
CView::OnLButtonDown(nFlags, point);
}
6)回车字符问题。
7)退格键处理:
用CDC类的GetBkColor函数获取背景色。设置背景颜色,利用CDC提供的另一个成员函数SetTextColor,函数声明如下:
virtual COLORREF SetTextColor(COLORREF crColor);
此函数会返回文本原来的颜色。保存返回值,后面把文本的颜色设置为原来的颜色。
从字符串中删除一个字符,利用CString类的Left,函数声明如下:
CString Left(int nCount)const;
此函数返回一个CString对象,返回字符串左边指定数目的字符。利用CString类的GetLength函数,可以得到指定字符串中字符的个数。
若当前输入的字符不是回车键或者退格键,就把它添加到m_strLine中,以便显示在屏幕上。
void CMFCTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获得当前设备描述表
CClientDC dc(this);
//定义文本信息结构体变量
TEXTMETRIC tm;
//获得设备描述表中的文本信息
dc.GetTextMetrics(&tm);
//判断是否为回车字符
if (0x0d == nChar) {
//回车符操作
m_strLine.Empty();
m_ptOrigin.y += tm.tmHeight;
}
else if(0x08==nChar)
{
//退格符操作
COLORREF bkColor=dc.GetBkColor();
//设置字体颜色为背景色,并返回原来的字体颜色
COLORREF oldColor=dc.SetTextColor(bkColor);
//删除字符串中当前插入符位置的字符
m_strLine = m_strLine.Left(m_strLine.GetLength() - 1);
dc.SetTextColor(oldColor);
}else
{
m_strLine += (wchar_t)nChar;
}
dc.TextOutW(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
CView::OnChar(nChar, nRepCnt, nFlags);
}
void CMFCTestView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
// 插入符移动到鼠标左键单击处的位置
SetCaretPos(point);
m_strLine.Empty();
m_ptOrigin = point;
CView::OnLButtonDown(nFlags, point);
}
void CMFCTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获得当前设备描述表
CClientDC dc(this);
//定义文本信息结构体变量
TEXTMETRIC tm;
//获得设备描述表中的文本信息
dc.GetTextMetrics(&tm);
//判断是否为回车字符
if (0x0d == nChar) {
//回车符操作
m_strLine.Empty();
m_ptOrigin.y += tm.tmHeight;
}
else if(0x08 == nChar)
{
//退格符操作
COLORREF bkColor=dc.GetBkColor();
//设置字体颜色为背景色,并返回原来的字体颜色
COLORREF oldColor=dc.SetTextColor(bkColor);
//重新输出文字
dc.TextOut(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
//删除字符串中当前插入符位置的字符
m_strLine = m_strLine.Left(m_strLine.GetLength() - 1);
//恢复到原来的字体颜色
dc.SetTextColor(oldColor);
}else
{
//将输入的字符追加到原来的字符后面
m_strLine += (wchar_t)nChar;
}
//获得特定字符串的宽度的高度
CSize sz = dc.GetTextExtent(m_strLine);
CPoint pt;
//插入符原来的纵坐标位置加上新插入字符串的长度
pt.x = m_ptOrigin.x + sz.cx;
pt.y = m_ptOrigin.y;
//重新设置插入符的位置
SetCaretPos(pt);
dc.TextOut(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
CView::OnChar(nChar, nRepCnt, nFlags);
}
4.1 设置字体
MFC提供了一个CFont类专门用来设置字体。此类派生于CGdiObject类,封装一个Windows图形设备接口(GDI)的字体。
实际编程中,构造一个CFont对象后,还必须利用该类提供的几个初始化函数之一对该对象进行初始化,然后才能使用此对象。
CFont类提供的初始化函数有:
CreateFont
CreateFontIndirect
CreatePointFont
CreatePointFontIndirect
这些初始化函数的作用主要将CFont这个C++对象与字体资源关联。
BOOL CreatePointFont(int nPointSize, LPCTSTR lpszFaceName,CDC* pDC=NULL);
参数
-
nPointSize: 设置将要创建的字体的高度。单位是一个点的十分之一。
-
lpszFaceName:字体的名字。VC++开发环境支持的字体颜色,可以看到这些字体的名称。方法:在工具–>选项–>字体和颜色
-
pDC:CDC对象指针,用于把nPointSize中指定的高度转化成逻辑单位。
当创建一个字体对象并初始化后,必须将它选入设备描述表,这个新字体才能发挥作用。
void CMFCTestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//获得当前设备描述表
CClientDC dc(this);
CFont font;
font.CreatePointFont(300, _T("华文行楷"), NULL);
CFont* oldFont = dc.SelectObject(&font);
//定义文本信息结构体变量
TEXTMETRIC tm;
//获得设备描述表中的文本信息
dc.GetTextMetrics(&tm);
//判断是否为回车字符
if (0x0d == nChar) {
//回车符操作
m_strLine.Empty();
m_ptOrigin.y += tm.tmHeight;
}
else if(0x08 == nChar)
{
//退格符操作
COLORREF bkColor=dc.GetBkColor();
//设置字体颜色为背景色,并返回原来的字体颜色
COLORREF oldColor=dc.SetTextColor(bkColor);
//重新输出文字
dc.TextOut(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
//删除字符串中当前插入符位置的字符
m_strLine = m_strLine.Left(m_strLine.GetLength() - 1);
//恢复到原来的字体颜色
dc.SetTextColor(oldColor);
}else
{
//将输入的字符追加到原来的字符后面
m_strLine += (wchar_t)nChar;
}
//获得特定字符串的宽度的高度
CSize sz = dc.GetTextExtent(m_strLine);
CPoint pt;
//插入符原来的纵坐标位置加上新插入字符串的长度
pt.x = m_ptOrigin.x + sz.cx;
pt.y = m_ptOrigin.y;
//重新设置插入符的位置
SetCaretPos(pt);
dc.TextOut(m_ptOrigin.x, m_ptOrigin.y, m_strLine);
dc.SelectObject(oldFont);
CView::OnChar(nChar, nRepCnt, nFlags);
}
4.2 字幕变色功能
CDC类提供的输出文字的函数:DrawText,可以在指定的矩形范围内输出文字。声明如下:
int DrawText(
//指定输出的字符串
const CString& str,
//文字显示范围的矩形
LPRECT lpRect,
//指定文本的输出格式
UINT nFormat
);
DrawText函数实际上是把文字的输出局限在一个矩形范围内。当输出的文字太多,以至于超出设定的矩形范围时,此函数会截断输出的文字,只显示在设定矩形内能够显示的那部分文字。
定时器
CWnd类的SetTimer成员函数可以设置定时器,该函数的声明形式如下所示:
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND,UINT, DWORD) );
函数调用成功,将返回新定时器的标识。
int >CMFCTestView::OnCreate(LPCREATESTR>UCT lpCreateStruct) { if (CView::OnCreate(lpCreateStruct) == -1) return -1; // TODO: 在此添加您专用的创建代码 //=========字符插入符>============== //创建设备描述表 CClientDC dc(this); //定义文本信息结构体变量 TEXTMETRIC tm; //获得设备描述表中的文本信息 dc.GetTextMetrics(&tm); //根据字体大小,创建合适的插入符 CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight); SetTimer(1, 100, NULL); ShowCaret(); return 0; }
处理定时器消息:
void CMFCTestView::OnTimer(UINT_PTR nIDEvent) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CView::OnTimer(nIDEvent); }
此响应函数有一个参数,nIDEvent,这是定时器的标识。一个应用程序中,可以设置多个定时器,每个定时器都有自己的时间间隔和标志符。但所有的定时器都发送WM_TIMER消息。所以需要通过nIDEvent参数获得当前是哪个定时器发送的定时器消息,然后根据不同的定时器做不同的处理。
需要让DrawText函数的第二个参数,即显示文字的矩形范围不断增加,所以需要设置一个变量,让其值不断增加。然后此变量赋值给矩形的宽度成员。所以添加视类成员函数m_nWidth并初始化为0。
本例对字符串资源进行变色处理。首先需要获取包围此字符串的矩形的位置,只需要获取矩形的高度。
1)矩形左上角的位置是此文字显示的起始坐标。
2)矩形的宽度由m_nWidth变量决定。
3)通过GetTextMetrics函数获取当前设备描述表的当前字体的高度,即为矩形的高度。
void CMFCTestView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//设置m_nWidth变量的值按照5个像素点不断增加
m_nWidth += 5;
//获得设备描述表中当前文字的实际高度。
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
//根据高度初始化矩形的大小
CRect rect;
rect.left = 0;
rect.top = 200;
rect.right = m_nWidth;
rect.bottom = rect.top + tm.tmHeight;
//设备描述表的字体颜色换成红色
dc.SetTextColor(RGB(255, 0, 0));
//根据字符串资源ID获得要显示的字符串内容
CString str;
str.LoadString(IDS_STRING101);
//在指定范围内输出字符串
dc.DrawText(str, rect, DT_LEFT);
CView::OnTimer(nIDEvent);
}
因为定时器每隔100ms就会发出一次WM_LTIMER消息,也就是每隔100ms, OnTimer函数就会被调用一次,每调用一次,矩形的宽度就会增加5个像素点。所以,以红色输出的文字范围就会增加一些。
上述代码中, DrawText函数使用的输出格式,即它的第三个参数使用的是DT_LEFT,这是一种左对齐格式。
将第三个参数换成DT_RIGHT显示:
在这个Text程序运行时,我们发现还有一些问题。其中一个问题是,当以DT_RIGHT输出格式显示文字时,在字符串全部输出完毕后,应该让它从头开始输出,而不是随着限制显示范围的矩形的宽度不断加大,而慢慢地从程序窗口上消失了。
实现此功能要判断限制显示范围的矩形宽度是否超过了需要显示的字符串在屏幕上显示时的宽度。而要获取字符串在屏幕上显示时的宽度,需要用到GetTextExtent函数。
void CMFCTestView::OnTimer(UINT_PTR nIDEvent)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//设置m_nWidth变量的值按照5个像素点不断增加
m_nWidth += 5;
//获得设备描述表中当前文字的实际高度。
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
//根据高度初始化矩形的大小
CRect rect;
rect.left = 0;
rect.top = 200;
rect.right = m_nWidth;
rect.bottom = rect.top + tm.tmHeight;
//设备描述表的字体颜色换成红色
dc.SetTextColor(RGB(255, 0, 0));
//根据字符串资源ID获得要显示的字符串内容
CString str;
str.LoadString(IDS_STRING101);
//在指定范围内输出字符串
dc.DrawText(str, rect, DT_RIGHT);
//判断输出的字符串长度与矩形的长度关系
CSize sz = dc.GetTextExtent(str);
if (m_nWidth > sz.cx) {
m_nWidth = 0;
dc.SetTextColor(RGB(0, 0, 255));
dc.TextOut(0, 200, str);
}
CView::OnTimer(nIDEvent);
}
该字符串在屏幕上显示时的宽度。一旦发现其超过了,就将该矩形宽度设置为0,让文本重新开始输出。并将设备描述表中文本的颜色设置为绿色,但此时,先前已输出到窗口中的文本的颜色并未改变,因此还需要再调用一次TextOut函数,在原位置以新的颜色重新输出文本。