文本编程之插入符

常用的文本处理程序有word,记事本、IDE集成开发环境等,它们都可以文本的编辑,鼠标点击之处都有一条闪烁的竖线,这个竖线就是插入符(Caret)。该插入符用于提示用户输入文字,下面就演示插入符的应用实例。


接口函数


在Cwindow成员中有一个Caret Methods,在这个Caret Methods中介绍了插入符的创建和使用,其接口函数如下:

//方法1:Creates a solid rectangle for the system caret.
BOOL CreateSolidCaret(int nWidth,int nHeight) throw();
//方法2:Creates a gray rectangle for the system caret.
BOOL CreateGrayCaret(int nWidth,int nHeight) throw();
//方法3:Creates a new shape for the system caret.
BOOL CreateCaret(HBITMAP pBitmap) throw();

//Hides the system caret. 
BOOL HideCaret( ) throw();
//Displays the system caret.
BOOL ShowCaret( ) throw();


插入符需要在窗口上显示,在单文档工程中有两个窗口,一个是框架类窗口和视类窗口,我们应该在视类窗口上进行操作,当创建了视类窗口后,就可以创建和显示插入符了。我们需要手动添加WM_CREATE消息响应函数,具体代码如下:

int CMFC_TestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
		
    CreateGrayCaret(3,20);//创建
    ShowCaret();//显示
	
    return 0;
}

                          图1 插入符运行效果


为了插入符能够跟随文本字体大小而发生变化,我们需要获得设备描述表中字体结构。在CDC类中有个GetTextMertics成员函数可以得到设备描述表中字体信息,其函数声明如下:

BOOL GetTextMetrics(LPTEXTMETRIC lpMetrics) const;

其中,入参是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;
其中tmHeight是字符高度,tmHeight = tmAscent + tmDescent, tmAveCharWidth是平均宽度,因为每个字符宽度都不同,只有一个平均宽度,如图2是字体信息的部分示意图。


                                        图2 字体信息示意图


有了字体信息,我们可以利用字体信息来,完善我们的插入符大小,具体代码如下:

int CMFC_TestView::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
    if (CView::OnCreate(lpCreateStruct) == -1)
        return -1;
    
    //方法2:
    //创建设备描述表
    CClientDC dc(this);
    //定义文本信息结构体
    TEXTMETRIC tmInfo;
    //获得设备描述表中文本信息
    dc.GetTextMetrics(&tmInfo);
    //根据当前字体大小,设置合适的插入符
    CreateSolidCaret(tmInfo.tmAveCharWidth / 4,tmInfo.tmHeight);
    //显示插入符
    ShowCaret();
	
    return 0;
}
运行效果:


        图3 根据字体大小创建的插入符


字符输入功能


下面要实现字符输入功能,也就是用户在键盘上输入字符时,插入符随着字符往后移动,按下回车键实现换行,按下回退键实现字符删除,按下鼠标左键时,就在当前文字显示插入符。为了捕获字符输入信息,我们需要添加Onchar消息响应函数。


1.插入符的移动实现

我们捕获鼠标左键按下信息(WM_LBUTTONDOWN),利用SetCaretPos()函数实现鼠标点击时位置的移动,代码实现如下:

void CMFC_TestView::OnLButtonDown(UINT nFlags, CPoint point)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值
    m_ptCaretOrigin = point;// 字符输入起始位置
    SetCaretPos(point);     // 插入符移动
    m_strLine.Empty();      //变化起始位置,清空已有字符内容
    CView::OnLButtonDown(nFlags, point);
}

当我们不断输入字符时,插入符也要不断发生变化,我们可以利用CDC类中GetTextExtent函数,来获得一个字符串在显示屏上显示的宽度和高度,函数声明如下:

CSize GetTextExtent(LPCTSTR lpszString,int nCount) const;
CSize GetTextExtent(const CString& str) const;
CSze有个两个成员变量,cx表示宽度,cy表示高度。

2.字符输入处理

    利用人眼的视觉残留效应,每来一个字符消息时,我们就重新输入所有的字符,用户感觉不到其中的变化,表现的效果就是用户输入字符,显示器就多出现一个该字符。


3.回车字符处理

   当按下回车键时,需要清空已有字符内容,同时计算新的字符输出位置,新的位置和原始位置相比,横坐标不变,纵坐标增加一个字符高度,高度消息可由GetTextMetrics函数来获得。


4.退格键处理

   按退格键实现字符的删除,我们可先设置字符和背景颜色相同的形式,实现字符的“删除”功能,然后在m_strLine中删除最后一个字符,同时将字体颜色设置回默认颜色,最后再输出字符串。


以上的功能实现代码如下:

void CMFC_TestView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags)
{
    // TODO: 在此添加消息处理程序代码和/或调用默认值

    CClientDC dc(this);


    TEXTMETRIC tm;
    dc.GetTextMetrics(&tm);

    if (0x0d == nChar)
    {
        //换行清空字符串信息
        m_strLine.Empty();
        //换新行
        m_ptCaretOrigin.y += tm.tmHeight;
    } 
    else if (0x08 == nChar)
    {
        //回车删除功能
        COLORREF cl = dc.SetTextColor(dc.GetBkColor());
        dc.TextOut(m_ptCaretOrigin.x, m_ptCaretOrigin.y, m_strLine);
        //新字符串输出
        m_strLine = m_strLine.Left(m_strLine.GetLength() - 1);
        dc.SetTextColor(cl);
    }
    else
    {
        m_strLine += (unsigned char)nChar;
    }

    //插入符位置变化
    CSize sz = dc.GetTextExtent(m_strLine);//获得一行字体的高度和宽度
    CPoint pt;
    pt.x = m_ptCaretOrigin.x + sz.cx;
    pt.y = m_ptCaretOrigin.y;
    SetCaretPos(pt);
    
    //放在最后,可以避免插入符显示痕迹
    dc.TextOut(m_ptCaretOrigin.x, m_ptCaretOrigin.y, m_strLine);

    CView::OnChar(nChar, nRepCnt, nFlags);
}
运行效果:


            图4 字符输入演示

转载于:https://www.cnblogs.com/jinxiang1224/p/8468379.html

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值