VC控件中拦截回车键
- 博客分类:
- 技术杂绘
VC控件中拦截回车键
2010年07月19日
本文讲述了在指定的编辑框上能响应从键盘输入回车键的一种方法,对进程内消息的解析、动态获取指定资源ID等技术也作了简要描述。
一、引言
在通常的以CEditView为基类的单文档/多文档视图程序中,可以很好的响应键盘输入的回车键,只需比较最近两次的输入的字符,看看最新输入的字符是否内码是13(0x0d,回车键的内码)即可识别出来,而要单独把一个编辑框放入对话框中却根本不响应,这个看似简单的问题在实际应用中还是解决起来比较困难的。尤其是当一个充当表单录入的对话框上有若干个编辑框,这就要求在一个编辑框添完一项表单后用习惯的回车键将该编辑框上的数据读取到内存中去,并自动将光标移动到下一个编辑框中准备填写下一栏表单。无疑这种界面是十分人机友好的,使录入人员不必去执行每填一下表单就去按一下执行读入到缓存功能的按钮的烦琐操作。但上述功能的实现却并不象其演示的功能那样简单,下面本文就对这项技术的实现及附带的其他技术作简要的介绍。
二、不能响应回车键的原因分析
之所以在以CEditView作为基类的程序中可以响应回车键,是由于该程序的视类本身就是一个Edit控件,这就是问题的关键所在。CEditView作为CView的派生类能响应从键盘输入的各种消息,其中有和键盘输入相关的WM_CHAR、WM_KEYDOWN、WM_KEYUP等消息。我们就可以在这些消息的响应函数中灵活地设计程序去捕捉到回车键的输入,并执行响应的操作。
当我们将编辑框作为一个普通的控件放到对话框上时情况就发生了变化。在此我们以CFormView为例,它也是CView的一个派生类,视是一个Form窗体(即对话框),当放有编辑框的窗体有回车键输入时,由于只有编辑框可以接受从键盘输入的字符,所以当键盘按下时统统把消息都发给了编辑框(在Windows下每个窗口、按钮、编辑框都看作一个窗口,都可以接受消息),可以通过ClassWizard在"Object IDs"选中编辑框所对应的ID号,在右边的消息框中可以看出该编辑框并不能响应WM_CHAR等消息,只能用EN_CHANGE事件来做类似的响应。可当我们加入了对该事件的处理函数时,却又将回车键当作控制字符,当输入回车键并不会激发EN_CHANGE事件,也就是说用这种方法仍旧无法捕获回车键的输入。
三、拦截回车键的思路与方法
Windows操作系统下各个窗口、控件归根结底都是通过系统的各种各样的消息来相互协调、相互联系的,而我们所遇到的这个问题换到消息的角度说就是"如何使程序能响应在编辑框上输入的回车键所发出的消息",只要能响应到这个消息,剩下的工作都可以在消息处理函数中完成。所以有必要对Windows系统的消息机制做些了解。
每个Windows应用程序开始执行后,Windows都为该程序创建一个"消息队列(message queue)",用来存放邮寄给该程序可能创建的各种不同窗口的消息。消息队列中消息的结构(MSG)为:
typedef struct tagMSG{
HWND hwnd;//窗口句柄,标识接收消息的窗口。
UINT message;//消息标识号,如WM_TIMER等。
WPARAM wParam;//消息参数,当为键盘消息时,表示虚拟键码如VK_RETURN等。
LPARAM lParam;//消息参数。
DWORD time;//邮寄消息的时间。
POINT pt;//邮寄消息时的光标位置,用屏幕坐标表示。
}MSG;
在系统下最常用的消息循环是调用GetMessage()函数从消息队列中取出消息,然后调用DespatchMessage() 函数让系统把消息发送给窗口函数,一般情况下其结果是把窗口的所有消息都传送给窗口函数。但特殊情况下可以在GetMessage()函数获得消息而又没发送出去之前,通过TranslateMessage()函数可以中途对消息进行解析,可以对指定的消息进行拦截,拦截后即可以照样发送出去,也可以不继续发送,完成对该消息的拦截,下面代码是该过程的示例:
MSG msg;
while(GetMessage(&msg,NULL,NULL,NULL,NULL){
TranslateMessage(&msg);
…… //对拦截的消息进行处理
DispathchMessage(&msg);
}
由于按下回车键时把产生的消息加入到消息队列中了,也传给了编辑框,但仅仅是由于编辑框没有能力处理该消息而造成了无法对回车键的响应,所以可以在消息循环里在把消息发送到编辑框之前就对消息进行拦截,并对其进行处理。其效果同编辑框响应回车键是一样的,仅在时序上有所提前而已。上述代码是在SDK(Software Develope Kits)下使用的,在MFC(Microsoft Foundation Class)下早已对其进行了封装,可以通过重载虚函数PreTranslateMessage()对所关心的消息进行解析:
BOOL CTestView::PreTranslateMessage(MSG* pMsg)
{
if (WM_KEYFIRST message && pMsg->message wParam==VK_RETURN )
{
UpdateData(TRUE);
AfxMessageBox(m_Text);
}
}
return CFormView::PreTranslateMessage(pMsg);
}
在上面的代码中,首先将pMsg->message所表示的消息同WM_KEYFIRST 和WM_KEYLAST比较,确定是键盘消息,然后通过消息参数pMsg->wParam的值来判断是否是回车键(VK_RETURN,虚拟键码可以从SDK相关资料查到)。如是,则可以将已输入到编辑框中的字符读取到m_Text中,并将其显示出来。
四、对编辑框的识别
前面已经可以对回车键响应了,可一个表单窗体有若干个编辑框,其各自的处理方式不尽相同,这就有必要对编辑框进行识别、对不同的编辑框做不同的处理。而且当按下回车键时必须保证只有当前有焦点的编辑框能完成对回车键的响应动作,否则也就失去了实际意义。
在Windows下的程序中,所有的资源都是有唯一标号的,使每个资源对象能唯一的区别于其他资源,所以我们可以通过资源ID来对编辑框做出区别,使之完成各自的响应处理。在Microsoft Visual C++ 6.0下可以通过"View"菜单的"ID= Resource Symboles…"查到指定ID的资源标识号的实际数值,如在本例中的两个编辑框IDC_EDIT1和IDC_EDIT2所对应的数值分别为1000和1001,对前面的解析消息的代码做些改动,主要如下所示:
……
if(pMsg->wParam==VK_RETURN )
{
HWND hWnd=::GetFocus();
int iID=::GetDlgCtrlID(hWnd);
if(iID==1000)//第一个编辑框的标识为1000
{
UpdateData(TRUE);
AfxMessageBox(m_Text1);//显示第一个编辑框的内容
}
if(iID==1001) //第二个编辑框的标识为1001
{
UpdateData(TRUE);
AfxMessageBox(m_Text2);//显示第二个编辑框的内容
}
}
……
在此通过API函数::GetFocus()(注意前面的"::",标识是全局API函数,而非某个类中的成员函数)取得当前光标所处的(即有焦点的)编辑框的句柄,然后通过API函数::GetDlgCtrlID()根据这个句柄返回此窗口资源的ID 号,该ID号是动态获取的,使之同预先查看好的编辑框的ID作下比较即可区分出是需要哪个编辑框对回车键作出响应。
小结:
本文通过对消息的解析实现了对特定编辑框的回车键的响应,在对消息机制有了基本的了解之后,可以用与本文类似的方法,对代码稍作改动,就可以使其他一些不能响应特殊消息的控件能接收、处理特定的消息。
注:以上方法可能处理的消息可能会相应两次,改成以下代码即可仅相应一次:
if(pMsg->message==WM_CHAR)
{
if(pMsg->wParam==0x0d)
{
HWND hWnd=::GetFocus();
int iID=::GetDlgCtrlID(hWnd);
if(IDC_EDIT_PAYMENT==iID)
{
double customed,payment;
CString temp;
((CEdit*)GetDlgItem(IDC_EDIT_CONSUMED))->GetWindowText(temp);
customed=atof(temp);
((CEdit*)GetDlgItem(IDC_EDIT_PAYMENT))->GetWindowText(temp);
payment=atof(temp);
if(payment<customed)
{
MessageBox("支付的金额不足,请重新输入!","错误");
return 0;
}
}
}
}
发表评论
-
java面笔试总结
2012-01-20 01:42 560java面笔试总结 2011年04月10日 2010、1 ... -
从solaris向linux移植应用程序的技术指导
2012-01-20 01:42 908从solaris向linux移植应用 ... -
memcached完全剖析
2012-01-20 01:42 403memcached完全剖析 2011年0 ... -
Oracle查询慢的原因
2012-01-20 01:42 538Oracle查询慢的原因 2010年11月25日 核心提 ... -
memcached完全剖析
2012-01-20 01:42 626memcached完全剖析 2011年0 ... -
电脑故障以及解决百科全书(电脑知识四十七)2
2012-01-19 09:30 505电脑故障以及解决百科 ... -
如何将Windows XP加速到极限
2012-01-19 09:30 621如何将Windows XP加速到极 ... -
相册管理类
2012-01-19 09:30 741相册管理类 2009年08月09日 ... -
fzl图片说。非主流
2012-01-19 09:30 775fzl图片说。非主流 2012年01月10日 非主流图片 ... -
Debug和Release区别
2012-01-17 02:05 652Debug和Release区别 2011年1 ... -
网络编程的一些笔记
2012-01-17 02:05 626网络编程的一些笔记 2010年08月14日 今天辛苦比 ... -
TGraphic
2012-01-17 02:05 1048TGraphic 2010年06月10日 ... -
在批处理中等待/延迟/暂停一定的时间
2012-01-17 02:05 1793在批处理中等待/延迟/ ... -
小学总写600字的作文
2012-01-15 21:34 539小学总写600字的作文 2009年11月24日 某年某月 ... -
学生操行评语
2012-01-15 21:34 537学生操行评语 2011年01月07日 优等生: 1 ... -
演讲稿大全
2012-01-15 21:34 548演讲稿大全 2010年11月17日 演讲稿大全 ?? ... -
笑话大全
2012-01-15 21:34 502笑话大全 2009年10月14日 不能随便起外号有个顽皮 ...
相关推荐
VC常用控件 VC常用控件 VC常用控件
VC 控件实例VC 控件实例VC 控件实例VC 控件实例VC 控件实例
VC控件相关的一些代码,包括List,进度条,Combox ,编辑框,树形控件等。
VC控件的使用方法说明,可以通过此轻松学习VC控件
内含强大的vc控件使用源代码,共有29个源代码示例,含有各种控件的高级使用方法和使用技巧。
本程序告诉你如何改变对话框中回车键的行为,并为。在不少程序中,我们点回车键要么代表确认要么是程序退出,好像是系统默认的动作,这实际挺烦人,那么如何改变这种状况,通过这个实例,你会找到其它的方法。编译时...
关于MFC控件的资料,16类VC控件使用例子,网上找的。
按键控件 不能用的我不传 vc6.0可用
这个文件包含了几乎所有的VC控件,对于初学者很有用
vc中控件的使用及操作方法
一个利用VC控件MSCOMM开发的串口通信程序 可运行!
原创-音频播放控件-MusicPlayer VC控件 音乐播放控件 ~~~~~~~~由于制作匆忙,没测试使用效果,欢迎反馈QQ:421458119~~~~~~ 可播放音乐格式: mp3,wma,mid 方法: _播放音乐 _设置音量 _暂停播放 _继续播放 _...
vc 控件自绘,包括按钮,静态文本框,列表框,树形控件
一个生成圆形气泡提示的VC 控件源码 示例演示,用于在输入框上显示的提示,其它地方也可以用,是接近圆形的椭圆形提示,和Windows的圆角矩形原理相似,只是外形上的区别,本气泡提示控件的使用步骤: 1. create ...
VC常用控件介绍,方便大家学习和使用VC控件
vc 透明控件背景源码推荐vc 透明控件背景源码推荐vc 透明控件背景源码推荐vc 透明控件背景源码推荐vc 透明控件背景源码推荐vc 透明控件背景源码推荐
VC串口控件编程 VC串口控件编程 VC串口控件编程 VC串口控件编程 VC串口控件编程 VC串口控件编程 VC串口控件编程 VC串口控件编程
用VC控件实现的modbus通信实验程序,用MSComm控件实现PC与三块智能电表通信,读取电压、电流和电量。
VC为CStatic控件添加超级连接 vc界面编程
各种VC源代码,自学VC的捷径。包括VC串口通信,VC贪吃蛇,VC与PLC通信,优美的VC控件开发等等,都是源代码,