打字时,一个字符一个字符输入。当输入一个新的字符时,实际上是重新输入了一个字符串,因为每个字符的宽度不定。因为人眼有视觉残留效应,所以感觉是一个字符一个字符地输入。
因此实现该功能:首先给CTestView类添加WM_CHAR消息响应函数OnChar。
接着给CTestView类添加CString类型的成员变量:m_strLine,用来存储输入的字符串,同时在CTestView类构造函数中初始化为空。
鼠标点击哪里,插入符就应该移动到哪里,字符就在插入符后输入。
因此给视类添加WM_LBUTTONDOWN的消息响应函数。
把插入符移动到鼠标左键单击处,利用CWnd类的SetCaretPos函数来实现。
鼠标左键单击,插入符移动到鼠标左键单击处时,m_strLine中之前保存的输入内容得清空,重新保存新的内容到m_strLine中,用到CString类的Empty函数。
OnChar函数中需要用到鼠标左键单击的坐标,为视类添加CPoint类型变量:m_ptOrigin,访问权限为私有。在视类构造函数中设置为0。
按下回车键,插入符换到下一行,之前保存的字符串清零,插入符位置横坐标不变,纵坐标加上当前字体你的高度,调用GetTextMetrics函数。
按下退格键删除一个字符,由于每个字符宽度不定,因此:
先将文本颜色设置为背景色,输出一次;将m_strLine中字符串末尾的字符删去,产生新的m_strLine,在将文本的颜色恢复为原来的颜色,再输出一次。
获取背景色:CDC类GetBKColor函数
设置文本颜色:CDC类SetTextColor函数
virtual COLORREF SetTextColor( COLORREF crColor );
返回的是先前文本的颜色。
从字符串中删除一个字符:CString类Left函数
CString Left( int nCount ) const;
返回一个CString对象,返回指定字符串左边指定数目(nCount)的字符。
若当前不是回车符和退格符,就把它添加到m_strLine变量中。
回车符ASCII码十六进制0x0d,退格符0x08。
void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
if(0x0d==nChar)
{
m_strLine.Empty();
m_ptOrigin.y+=tm.tmHeight;
}
else if(0x08==nChar)
{
COLORREF clr=dc.SetTextColor(dc.GetBkColor());
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);
m_strLine=m_strLine.Left(m_strLine.GetLength()-1);
dc.SetTextColor(clr);//恢复之前的文本颜色
}
else
{
m_strLine+=nChar;
}
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);
CView::OnChar(nChar, nRepCnt, nFlags);
}
这个时候插入符是固定不动的,这个时候我们要让插入符随着字符的输入、删除和回车而移动。
在dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);之前加入以下代码:
CSize sz=dc.GetTextExtent(m_strLine);
CPoint pt;
pt.x=m_ptOrigin.x+sz.cx;
pt.y=m_ptOrigin.y;
SetCaretPos(pt);
5.4.1设置字体
MFC提供了一个CFont类来专门设置字体。
在构造了一个CFont对象后,利用该类提供的初始化函数对对象进行初始化,然后才能使用该对象。
本例使用CreatePointFont函数进行初始化。
BOOL CreatePointFont( int nPointSize, LPCTSTR lpszFaceName, CDC* pDC = NULL );
第一个参数设置字体的高度,单位是一个点的十分之一。
第二个参数是字体的名称
第三个参数CDC对象指针,将第一个参数指定高度转换为逻辑单位,若为NULL,就用屏幕设备描述表进行转换。
void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
// TODO: Add your message handler code here and/or call default
CClientDC dc(this);
CFont font;
font.CreatePointFont(300,"华文行楷",NULL);
CFont *pOldFont=dc.SelectObject(&font);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
if(0x0d==nChar)
{
m_strLine.Empty();
m_ptOrigin.y+=tm.tmHeight;
}
else if(0x08==nChar)
{
COLORREF clr=dc.SetTextColor(dc.GetBkColor());
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y,m_strLine);
m_strLine=m_strLine.Left(m_strLine.GetLength()-1);
dc.SetTextColor(clr);//恢复之前的文本颜色
}
else
{
m_strLine+=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(pOldFont);
CView::OnChar(nChar, nRepCnt, nFlags);
}
5.4.2字幕变色功能的实现
为了输出卡拉OK字幕的平滑变色效果,调用CDC类的DrawText函数。
int DrawText( const CString& str, LPRECT lpRect, UINT nFormat );
第一个参数:指定要输出的字符串。
第二个参数:指定文字显示的矩形。
第三个参数:指定文本的输出格式。
初始时,将文本矩形的宽度设置为较小的值,然后不断增加矩形的宽度,然后达到文字平滑变色的效果。要实现这个功能,要用到定时器。
定时器消息响应函数中,不断地增加显示文字的矩形宽度。
CWnd类SetTimer成员函数可以设置定时器。
UINT SetTimer( UINT nIDEvent, UINT nElapse, void (CALLBACK EXPORT* lpfnTimer)(HWND, UINT, UINT, DWORD) );
第一个参数:非零值的定时器标识,函数成功调用就返回它。
第二个参数:定时器的时间间隔,以毫秒为单位。
第三个参数:回调函数,若设置了回调函数,就用它来处理定时器消息。
我们在视类OnCreate函数中设置定时器。即窗口产生之前。
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CView::OnCreate(lpCreateStruct) == -1)
return -1;
bitmap.LoadBitmap(IDB_BITMAP1);
CreateCaret(&bitmap);
ShowCaret();
SetTimer(1,100,NULL);
// TODO: Add your specialized creation code here
return 0;
}
接着给视类定时器消息WM_TIMER消息添加消息响应函数。
void CTextView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CView::OnTimer(nIDEvent);
}
参数是定时器标识,区别那个定时器发来的消息。
因为DrawText函数第二个参数,矩阵的宽度需要不断增加,所以需要为CTestView类添加int型成员变量:m_nWidth。在视类构造函数中初始化为0。
对字符串资源(IDS_STRING61446)进行平滑变色。通过GetTextMetrics函数来获取矩阵的高度。
void CTextView::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
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));
CString str;
str.LoadString(IDS_STRING61446);
dc.DrawText(str,rect,DT_LEFT);
CView::OnTimer(nIDEvent);
}
DT_LEFT:格式左对齐。DT_GIGHT:右对齐。
唱卡拉OK时,字幕会随着音乐的播放而变成另一种颜色,同时还需要判断矩形的宽度是否超过了字符串的宽度。字符串宽度计算要用到GetTextExtent函数。
在最后添加以下代码:
CSize sz=dc.GetTextExtent(str);
if(m_nWidth>sz.cx)
{
m_nWidth=0;
dc.SetTextColor(RGB(0,255,0));
dc.TextOut(0,200,str);
}