1. 插入符:
插入符的创建一般放在CView类的OnCreate函数中,即WM_CREATE消息中。OnCreate是在窗口已经创建后才调用的。
a. 文本插入符
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm); //得到设备描述表中关于字体的信息
CreateSolidCaret(tm.tmAveCharWidth/8,tm.tmHeight); //创建插入符,除以8只是一个经验使用问题,发现除以8后,宽度和习惯中使用的较为吻合
ShowCaret(); //插入符创建后默认是hide的,所以必须调用此函数显示
结构体TEXTMETRIC:该结构体中包含了物理字体的基本信息
typedef struct tagTEXTMETRIC {
LONG tmHeight; //字体的高度
LONG tmAscent; //基线以上的部分
LONG tmDescent; //基线以下的地方
LONG tmInternalLeading;
LONG tmExternalLeading;
LONG tmAveCharWidth; //平均字符宽度
LONG tmMaxCharWidth; //最大字符宽度
LONG tmWeight;
LONG tmOverhang;
LONG tmDigitizedAspectX;
LONG tmDigitizedAspectY;
TCHAR tmFirstChar;
TCHAR tmLastChar;
TCHAR tmDefaultChar;
TCHAR tmBreakChar;
BYTE tmItalic;
BYTE tmUnderlined;
BYTE tmStruckOut;
BYTE tmPitchAndFamily;
BYTE tmCharSet;
} TEXTMETRIC, *PTEXTMETRIC;
b. 图形插入符
CBitmap bmp; //因为是是局部变量,所以在函数结束的时候会析构,因而不会出现图标,所以要将此变量声明为类的成员变量
if(bmp.LoadBitmap(IDB_BITMAP1))
{
CreateCaret(&bmp);
ShowCaret();
}
2. CString类没有基类。
特殊的一个用法:可以在资源视图中String Table可以定义个字符串资源,并且具有自己的资源ID号,可以用CString的LoadString方法加载一个字符串资源。
3. 在视图窗口中输出文字:
当窗口重绘的时候,即调整窗口的大小的时候,程序会发送WM_PAINT消息,应用程序框架类收到这个消息的时候,就会调用CView类中的OnDraw函数。如果想让窗口内容在窗口调整大小后仍然能显示在窗口上的话,可以将绘制窗口内容的代码写在OnCreate函数中。
路径层:在视图上指定一个区域,可以在该区域中做绘出图形文字等,别人是无法覆盖掉本路径层中的内容的。下例实现的就是这个功能。
CString str="hello world";
pDC->TextOut(50,50,str);
CSize size=pDC->GetTextExtent(str); //得到字符串的像素高度和宽度
pDC->BeginPath(); //开始路径层
pDC->Rectangle(50,50,50+size.cx,50+size.cy); //在字符串外部画一个矩形将之圈住
pDC->EndPath(); //结束路径层
pDC->SelectClipPath(RGN_DIFF); //SelectClipPath函数设置两个剪切区域间的交互模式。即现存的视图区域可以理解为一个剪切区域,上述路径层中设置矩形区域为另一个剪切区域,模式RGN_DIFF为从现有的剪切区域中排除掉路径层中设置的矩形剪切区域;模式RGN_ADD为只两个剪切区域的交集才进行如下的绘图操作。
for(int i=0;i<300;i+=10) //在视图窗口上画一个网状格
{
//画竖线
pDC->MoveTo(0,i);
pDC->LineTo(300,i);
//画横线
pDC->MoveTo(i,0);
pDC->LineTo(i,300);
}
注意方法GetTextExtent和GetTextMetrics的区别
按照用户的输入在视图窗口中输出字符:
在WM_CHAR消息,即OnChar函数中添加如下代码:
//以下功能仅实现简单的字处理,如果复杂的需求,则可以将CView类派生于CEditView或CRichEditView,这两个类已经具有各复杂的功能
CClientDC dc(this);
CFont font;
font.CreatePointFont(200,"新宋体",NULL); //设置字体
CFont *pOldfont=dc.SelectObject(&font);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
if(0x0d==nChar) //回车
{
m_strLine.Empty(); //新起一行,将原来行的内容清空
m_ptButton.y+=tm.tmHeight; //定位新的一行的其实坐标
}
else if(0x08==nChar) //退格
{
//下面的实现方式只是一种比较取巧的方式。
COLORREF clr=dc.SetTextColor(dc.GetBkColor()); //设置字体颜色
dc.TextOut(m_ptButton.x,m_ptButton.y,m_strLine); //利用上面的颜色输出原先一行内容,实现隐藏的功能,实际上是将原来的字符串覆盖掉了。
m_strLine=m_strLine.Left(m_strLine.GetLength()-1); //将最后一位的字符去除,达到退格的效果
dc.SetTextColor(clr); //颜色还原,会对最终的输出产生效果
}
else //正常输入
{
m_strLine+=nChar;
}
//以下代码设置插入符位置
CPoint pt; //插入符号的位置
CSize size=dc.GetTextExtent(m_strLine); //得到字符串的像素长度和高度
pt.x=m_ptButton.x+size.cx;
pt.y=m_ptButton.y;
SetCaretPos(pt); //设置插入符号的位置
dc.TextOut(m_ptButton.x,m_ptButton.y,m_strLine);
dc.SelectObject(pOldfont);
CView::OnChar(nChar, nRepCnt, nFlags);
4. CTimer:定时器
一般在WM_CREATE消息,即OnCreate函数中设置Timer,即调用SetTimer函数,第一个参数为Timer的ID,第二个为触发的间隔时间,其中第三个参数为消息处理函数,在MSDN中的解释是这样的,Specifies the address of the application-supplied TimerProc
callback function that processes the WM_TIMER messages. If this parameter is NULL, the WM_TIMER messages are placed in the application’s message queue and handled by the CWnd object.所以一般设置为NULL,交由WM_TIMER消息进行处理。其中OnTimer函数的原型为:void CTextView::OnTimer(UINT nIDEvent),在该函数中通过判断nIDEvent就可以区分是不同的定时器所触发的了。
5. 实现字幕滚动效果:
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
SetTimer(1,100,NULL); //设置timer
}
void CTextView::OnTimer(UINT nIDEvent)
{
m_nUnit+=5; //步进的长度
CClientDC dc(this);
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
CRect rect(0,200,m_nUnit,200+tm.tmHeight); //不断将矩形区域长度增加
CSize size=dc.GetTextExtent(m_strDefault);
if(rect.Width()<=size.cx)
{
COLORREF oldColor=dc.SetTextColor(RGB(255,0,0));
dc.DrawText(m_strDefault,rect,DT_RIGHT); //这是实现该功能的核心函数。该函数的功能就是在第二个参数指定的矩形区域内按照第三个参数设置的输出模式显示第一个参数指定的字符串。DT_RIGHT表示对指定字符串从右边开始显示在指定的矩形区域内,还有DT_LEFT则实现相反的功能
dc.SetTextColor(oldColor);
}
else
{
m_nUnit=0; //已经将字符串全部输出了,则重置,重新开始从左输出
COLORREF oldColor=dc.SetTextColor(dc.GetBkColor());
dc.TextOut(0,200,m_strDefault); //将原有内容用白色的字体覆盖,达到去除内容的效果
dc.SetTextColor(oldColor);
}
CView::OnTimer(nIDEvent);
}