VC++字符输入 ASCII码 您所在的位置:网站首页 如何输入ascii码输出字符串 VC++字符输入 ASCII码

VC++字符输入 ASCII码

2023-08-16 13:12| 来源: 网络整理| 查看: 265

目录

字符输入

接上:VC++路径

接下:

字符输入

下面要实现字符的输入功能,也就是当用户在键盘上按下某个字符按键后,要把该字符输出到程序窗口上。这就需要程序捕获键盘按下这一消息。之前曾介绍过WM_CHAR消息,这里,我们可以捕获这个消息,在该消息的响应函数中完成字符输出功能。但在字符输出时有一个问题需要注意,利用TextOut函数在窗口中输出字符时,需要提供字符显示位置的x坐标和y坐标,例如,我们打算在(0,0)位置处输出用户按键的字符,如果用户先后按下了“a”“b”“c”这三个字符,对于“a”字符,输出的位置是(0,0),紧接着我们要在“a”字符之后输出字符“b”,但我们如何才能确定“b”字符的输出位置呢?这在实现时有一定的难度,因为每个字符在屏幕上所占据的宽度都是不一样的,这样我们要获得下一个输入点的坐标就不太容易实现。为此,我们可以采取一种简单的方式,把每次输入的字符都存储到一个字符串中,例如,按下了“a”和“b”字符键之后,将这两个字符组成一个字符串:“ab”。当随后再按下“c”键后,再把它与“ab”组成一个字符串:“abc”。在程序中,每当按下新的字符时,都在窗口当前插入符的位置把这个字符串重新输出一次。因为人眼具有视觉残留的效应,因此,用户感觉不到这种重新输出的变化,只能感觉到每按下一个字符,窗口中就都多了一个字符。

遵照这种思路,我们继续在已有的 Text 程序中添加功能,让 CTextView 类捕获WM_CHAR消息,接着为该类定义一个私有的CString类型的成员变量:m_strLine,专门用来存储输入的字符串,并在 CTextView 类的构造函数中将这个变量初始化为空,初始化代码:

public: afx_msg void OnChar(UINT nChar, UINT nRepCnt, UINT nFlags); CString m_strLine; m_strLine = ""; void CTextView::OnChar(UINT nChar, UINT nRepCnt, UINT nFlags) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CView::OnChar(nChar, nRepCnt, nFlags); } void CTextView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 CView::OnLButtonDown(nFlags, point); }

这里仍有几个问题需要注意,第一个问题是,程序应该在当前插入符的位置输出字符。也就是说,在程序运行时,如果用鼠标左键单击窗口中某个位置,那么插入符就应该移动到这个地方,随后输入的字符都应在此位置处往后输出。这样的话,我们还需要捕获鼠标左键按下消息(WM_ LBUTTONDOWN),在该消息响应函数中,把插入符移动到鼠标左键的单击点处。这可以利用CWnd类的SetCaretPos函数来实现。该函数的声明形式为:

static void PASCAL SetCaretPos( POINT point );

从该函数的声明可以知道,它是一个静态函数,并带有一个 POINT 结构体类型的参数,该参数表示一个点。在本例中,这个点就是鼠标左键单击点。接下来,我们就可以在鼠标左键按下这一消息的响应函数中添加如下所示代码中加灰显示的那行代码,以完成插入符移动到当前鼠标左键单击点处的功能。

void CTextView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCaretPos(point); CView::OnLButtonDown(nFlags, point); }

编译并运行Text程序,然后用鼠标左键在程序窗口中任意位置处单击,将会发现插入符随着鼠标左键的单击而移动。程序结果如图所示。

第二个需要注意的问题是,用来存储输入的字符串的成员变量m_strLine的取值变化问题。当用鼠标左键单击窗口中一个新的地方时,插入符就会移动到这个新位置,那么以后输入的字符都应从这个位置处开始输出,而以前输入的字符不应再从此位置处重新输出,因此,这时就要把m_strLine中已有的内容清空。这可以利用CString 类的成员函数Empty来实现。于是,我们在上述例代码中添加Empty函数调用,清空m_strLine中的内容,结果如下例所示。

void CTextView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCaretPos(point); m_strLine.Empty(); CView::OnLButtonDown(nFlags, point); }

第三个问题是,每次输入的字符串都应在当前插入符位置,也就是鼠标左键单击点处开始显示,这样,就需要把鼠标左键单击点的坐标保存起来,以便在OnChar函数中使用。于是我们为CTextView类再增加一个CPoint类型的成员变量来保存这个坐标值,将这个变量取名为:m_ptOrigin,并将其访问权限设置为私有的。然后在CTextView类的构造函数中设置其初值为0;接着在鼠标左键按下这一消息的响应函数中保存当前鼠标单击点,代码如下例所示。

private: CPoint m_ptOrigin; CTextView::CTextView() noexcept { // TODO: 在此处添加构造代码 m_strLine = ""; m_ptOrigin = 0; } void CTextView::OnLButtonDown(UINT nFlags, CPoint point) { // TODO: 在此添加消息处理程序代码和/或调用默认值 SetCaretPos(point); m_strLine.Empty(); m_ptOrigin = point; CView::OnLButtonDown(nFlags, point); }

第四个问题是,在输出字符时,还应考虑到回车字符的处理。在按下回车键后,插入符应换到下一行,随后的输入也应从这一新行开始输出。这样就需要清空上一行保存的字符,并计算插入符在下一行的新位置。这时插入符的横坐标不变,纵坐标发生了变化,而利用已保存的当前插入点的纵坐标加上当前字体的高度就可以得到回车后插入符的新位置的纵坐标。使用前面已经介绍过的GetTextMetrics函数,即可获得当前设备描述表中字体的高度信息。

ASCII码

cr:表示回车,十进制的13。

void CTextView::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; } CView::OnChar(nChar, nRepCnt, nFlags); }

第五个问题是,在输出字符时,还要处理一个特殊的字符:退格键(即Backspace键,十进制08)。当按下退格键后,应当删除屏幕上位于插入符前面的那个字符,也就是将这个字符从屏幕上抹掉,同时,插入符的位置应回退一个字符。这个问题的处理也有一定的难度,但我们可以采用一种取巧的方式来实现。我们知道可以使用删除的方式让用户在屏幕上看不见这个字符。另外,如果文本的颜色与背景色一样的话,在屏幕上也看不到这个文本,给用户的感觉就是删除了这个文本。因此,我们可以先把文本的颜色设置为背景色,在窗口中把该文本输出一次。然后从保存输入字符的字符串变量(m_strLine)中把要删除的字符删除,再把文本的颜色设置为原来的颜色,之后再把字符串在窗口中输出一次。这时在屏幕上看到的就是正确的删除效果。因为这些操作都是连续的操作,而且执行的时间非常短,所以给用户的感觉就是一按退格键,就删除了插入符前面的那个字符。

在具体实现时,为了获取背景色,可以利用CDC类的GetBkColor函数。而设置文本颜色,可以利用CDC类提供的另一个成员函数SetTextColor,该函数的声明如下所示:

virtual COLORREF SetTextColor( COLORREF crColor );

这个函数将会返回文本先前的颜色。我们需要把这个返回值保存起来,因为后面还要把文本的颜色设置回先前的颜色再次显示。如果想要实现从字符串中删除一个字符,则可以利用CString类的Left函数,该函数的声明形式如下所示:

CStringT Left( int nCount ) const;

这个函数返回一个CString对象,即返回指定字符串左边指定数目(nCount参数指定)的字符。例如字符串的值为“Windows”,如果指定参数值为3,调用Left函数,那么将返回字符串:“Win”,即“Windows”左边的三个字符。因为本例要删除字符串最右边的那个字符,所以可以将Left函数的参数指定为待显示字符串中字符个数减去数值1后得到的数值。利用CString类提供的GetLength函数,可以得到指定字符串中字符的个数。

void CTextView::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 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); } CView::OnChar(nChar, nRepCnt, nFlags); }

如果当前输入的字符不是以上这两种特殊字符(回车键和退格键),就应该把它添加到m_strLine变量中,以便在屏幕上输出。

知识点 回车字符的ASCII码十六进制值是0x0d。退格键的ASCII码十六进制值是0x08。

解决了以上这些问题,就可以在WM_CHAR消息响应函数中进行字符输出的处理了,具体实现代码如下例所示。

void CTextView::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 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 += (TCHAR)nChar; } dc.TextOut(m_ptOrigin.x, m_ptOrigin.y, m_strLine); CView::OnChar(nChar, nRepCnt, nFlags); }

提示:上面代码使用了一个TCHAR数据类型,这主要是为了应对程序中对于ANSI和UNICODE字符的不同处理而定义的类型,便于我们对字符操作采用统一的处理方式。Visual Studio的编译器通过条件预处理指令来决定实际使用类型的字符。TCHAR的定义方式如下: 

#ifdef UNICODE typedef WCHAR TCHAR; #else typedef CHAR TCHAR;

编译并运行 Text 程序,将会发现程序现在能够在当前插入符位置处显示输入字符了,结果如图所示。

但是这个程序还有点问题,当在屏幕上输出字符时,插入符的位置并没有改变。正常来说,插入符应该随着字符的输入而移动。我们已经知道可以利用SetCaretPos函数来设置插入符的位置,但移动的位置如何确定呢?实际上,对于同一行上的输入来说,插入符横向移动的距离就是输入字符的宽度,而其纵坐标是不变的。根据前面的内容,我们知道利用GetTextExtent函数就可以得到字符串的宽度。因此,在上述例添加如下所示代码,以实现插入符随字符的输入而移动这一功能。 

CSize sz = dc.GetTextExtent(m_strLine); CPoint pt; pt.x = m_ptOrigin.x + sz.cx; pt.y = m_ptOrigin.y; SetCaretPos(pt); void CTextView::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 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 += (TCHAR)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); }

再次编译并运行Text程序,并输入任意字符,可以发现程序屏幕上插入符随着字符的输入而移动了。Text程序运行结果如图所示。这时,我们也可以试试回车键和退格键的效果,可以发现均成功实现所需功能。

接上:VC++路径 接下:


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有