Lesson4:文本编程
本文主要讲了在MFC中的文本编辑,并以简单的文本编辑为例,对光标显示、字符串输出、键盘按键输出字符,文字颜色字体设置和文字渐变效果进行了详细讲解。
1. 光标显示
文本编辑一般都会有一个光标,光标是在窗口创建之后才出现的,所以在view类里添加一个OnCreate消息处理程序,用于显示一闪一闪的光标。
int CTextView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if(CView::OnCreate(lpCreateStruct) == -1)
return -1;
// TODO: 在此添加您专用的创建代码
CClientDCdc(this); //定义一个cclientdc类的对象dc(创建设备描述表)
TEXTMETRIC tm; //定义一个文本结构体变量tm,用于保存得到的文本结构信息
dc.GetTextMetrics(&tm); //获得一个文本结构体,后面会用到它的成员变量宽度和高度
//CreateSolidCaret(tm.tmAveCharWidth/ 8, tm.tmHeight); //获得一个插入符(宽度,高度)
//ShowCaret(); //显示插入符
//也可以用设计的位图代表光标
//CBitmap bitmap;
//这里定义了一个局部的对象,当oncreate函数执行完毕后,bitmap这个对象完成析构,会将相关联的资源销毁,就看不到位图了,所以应该把它定义为view的成员变量
bitmap.LoadBitmap(IDB_BITMAP1);
CreateCaret(&bitmap);
ShowCaret();
return 0;
}
GetTextMetrics函数:函数功能是得到字体的度量信息,因为CDC类的GetTextMetrics成员函数要求参数是一个TEXTMETRIC结构体的指针,所以我们就定义一个TEXTMETRIC结构体的变量,将变量地址传给GetTextMetrics,通过GetTextMetrics函数用设备描述表中当前字体信息填充这个结构体。
2. 文字显示
ondraw函数:窗口发生重绘时,窗口中的文字或图形就被擦除掉。为了让文字一直保持在view类的窗口中,在Windows程序中提供的WM_PAINT函数,可以在WM_PAINT消息函数中将内容再输出,同样,在MFC中提供了一个类似WM_PAINT的函数,ondraw函数。
void CTextView::OnDraw(CDC* pDC)
{
CTextDoc* 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_WEIXIN); //通过字符串标示符,输出字符串
pDC->TextOut(0,200, str);
//通过路径层将输出的文章圈起来,对比下面画了线条后两行字的状态,一个被网格覆盖,一个没有覆盖
//实现路径层和剪裁区域的互操作达到相应效果。
pDC->BeginPath(); //在beginpath和endpath之间的矩形框 没有被线条穿过
pDC->Rectangle(50,50, 50 + sz.cx, 50 + sz.cy); //用一个矩形框把字符框起来,配合slectclippath 进行操作
pDC->EndPath();
pDC->SelectClipPath(RGN_DIFF); //互操作类型取决于SelectClipPath的参数
//画网格
for (int i = 0;i<300; i += 10)
{
pDC->MoveTo(0,i);
pDC->LineTo(300,i);
pDC->MoveTo(i,0);
pDC->LineTo(i,300);
}
}
CString类:字符串操作类,没有基类,一个CString对象可以有可变长度的字符组成。在C语言中,利用char指针操作字符串时,一旦分配了堆内存,那么内存大小就定了,要想另外多存,就要重新分配大小。而CString函数在操作字符串时,我们不需要配内存大小,在类的内部都完成了。
字符串加载方法1:
CString str("tianjin"); /* 也可以这样赋值: CString str; str=" tianjin "; */
pDC->TextOut(50, 50, str); //使用类成员函数输出字符串
字符串加载方法2:
str.LoadString(IDS_nan); //在资源视图的string table中添加一个字符串,名字为IDS_nan
pDC->TextOut(50, 150, str);
3. 输入字符
对于一个文本编辑器,当从键盘上按键时,应该显示出所按的键对应的字符,所以应该对按键消息onchar进行响应。按键中特殊的键是回车和退格键。并且在字符输入中常常需要改变文字的颜色和字体。
3.1 设置字体
字体设置中,在view类里定义一个CFont类型的变量m_font保存设置的字体,在菜单里增加一个按钮用来响应设置字体事件,按钮的ID为IDM_FONT,添加处理程序如下。
void CTextView::OnFont()
{
// TODO: 在此添加命令处理程序代码
CFontDialog dlg;
if (IDOK ==dlg.DoModal()) //弹出字体对话框,然后选择,点击ok确认选择
{
if(m_font.m_hObject)
m_font.DeleteObject(); //如果字体已绑定,则删除字体,否则第二次选择字体报错
m_font.CreateFontIndirectA(dlg.m_cf.lpLogFont); //选择字体
//Invalidate(); // 窗口重绘
}
}
3.2 设置颜色
颜色设置中,在view类里定义一个 COLORREF类型的变量m_clr保存设置的颜色,在菜单里增加一个按钮用来响应设置颜色事件,按钮的ID为IDM_COLOR,添加处理程序如下。
void CTextView::OnColor()
{
// TODO: 在此添加命令处理程序代码
CColorDialog dlg;
dlg.m_cc.Flags |= CC_RGBINIT|CC_FULLOPEN; //将先前标记和初始化或组合起来
dlg.m_cc.rgbResult =m_clr;
if (IDOK ==dlg.DoModal())
{
m_clr =dlg.m_cc.rgbResult;
}
}
3.3 输入显示
其中 CString m_strLine初始化为空,用来保存输入的字符串CPoint m_ptOrigin初始化为0,用来保存光标位置。
void CTextView::OnChar(UINT nChar,UINT nRepCnt, UINT nFlags)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//设置字体
CClientDC dc(this);
dc.SetTextColor(m_clr); //将设置的颜色选择到设备描述表中,改变文字颜色
//CFont font;
//font.CreatePointFont(300,"华文行楷", NULL);
CFont *pOldFont =dc.SelectObject(&m_font);//将字体选择到设备描述表中,并保存以前的字体到指针pOldFont
//按键处理
TEXTMETRIC tm;
dc.GetTextMetrics(&tm);
CreateSolidCaret(tm.tmAveCharWidth/ 8, tm.tmHeight); //修改字体后,如果没有这句代码显示不了光标,不知道为什么
if (0x0d == nChar) //回车键处理(0x0d)
{
m_strLine.Empty();//清空字符串,与下面光标位置没有关系
m_ptOrigin.x= 0; //设置新的光标x,y位置
m_ptOrigin.y+= tm.tmHeight;
}
else if (0x08 == nChar) //删除键处理(0x08),删除字符可以通过将最后一个字符设置为背景色,就看上去删除了字符
{
COLORREF clr= dc.SetTextColor(dc.GetBkColor());//获得背景色之前,保存先前的文本颜色到clr
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y, m_strLine);//输出字符,即现在字符都看不到了,和背景色一样
m_strLine =m_strLine.Left(m_strLine.GetLength() - 1);//取左边总数减1个字符
dc.SetTextColor(clr);
}
else
{
m_strLine +=(char)nChar;
}
//输入字符后,光标跟着移动,m_ptOrigin的位置只与鼠标点击位置有关
CSize sz =dc.GetTextExtent(m_strLine);
CPoint pt;
pt.x = m_ptOrigin.x +sz.cx;
pt.y = m_ptOrigin.y;
SetCaretPos(pt); //设置光标并显示
ShowCaret();
dc.TextOut(m_ptOrigin.x,m_ptOrigin.y, m_strLine);//输出字符,现在输出的就是看到的字符
dc.SelectObject(pOldFont);//恢复到以前的字体
CView::OnChar(nChar, nRepCnt,nFlags);
}
在文本编辑中,当我们点击鼠标时,光标应跟着移动。通过OnLButtonDown捕获这个消息
void CTextView::OnLButtonDown(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
SetCaretPos(point); //设置鼠标点击位置为光标位置
m_strLine.Empty(); //点击鼠标后,位置已换,因此要清空字符串,从新开始计算输入字符串的长度
m_ptOrigin = point;
CView::OnLButtonDown(nFlags,point);
}
4. 字符颜色渐变效果
为了产生渐变效果,我们可以用一个定时器,在定时器里进行颜色渐变。添加WM_ONTIEMR消息进行处理。
在oncreate函数中设置一个定时器,当窗口产生的时候就调用这个定时器。
void CTextView::OnTimer(UINT_PTR nIDEvent=1)
{
// TODO: 在此添加消息处理程序代码和/或调用默认值
//产生渐变的速度
m_nWidth += 5;//按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_WEIXIN);
dc.DrawText(str, rect,DT_LEFT);
//在150处再次输出字符串
rect.top = 150;
rect.left = 50;
rect.bottom = rect.top+ tm.tmHeight;
dc.DrawText(str, rect,DT_RIGHT);
//如果显示结束,又从新显示
CSize sz =dc.GetTextExtent(str);
if (m_nWidth>sz.cx)
{
m_nWidth =0;
dc.SetTextColor(RGB(0,255, 0));
dc.TextOut(0,200, str);
}
CView::OnTimer(nIDEvent);
}