Henry手记 - Datagrid键盘事件响应(二)
韩睿 ( 03/11/2003)
这篇文章写得有点晚,继上一篇推出已经快两个月了,今天看到一名网友的留言,说他还在等着看对“Enter”事件的处理,连忙放下手中的事,补上这一篇,也希望网友们不会太失望。
对于Datagrid的键盘事件响应,我们一定要分辨清楚是Datagrid自身的,还是cell单元格的键盘事件响应,处理方法是有很大区别的。大家可以参考第一篇的方法,对cell中的键盘事件进行处理。
但有个问题上一节没有交待,就是如何对Enter键、方向键、Tab键、Pgup/PgDn这些虚键进行拦截与处理?一般网友遇到这个问题,十有八九是出于这个目的:就是希望按Enter键时使光标在一行中向右一个格一个格跳(从“name”到“123”),而不是立即跳向同一列的下一行(到“xxx”)。(如图1所示)
图1 跳格演示
但是,我们在上一篇中用尽方法也截不下Enter键呀,看来这一键盘响应已经被控件封装为protected型了。控件编写人员把多个预定义的键盘绑定方案封装起来,称为快捷键。我们在Keydown/KeyPress中没办法拦截到Enter键和其它一些键盘按键正是这个原因,下面罗列的就是隐藏起来的快捷键:
操作
快捷键
完成单元格输入并向下移动到下一个单元格。
如果焦点在子表链接上,则导航至该表。
ENTER 键
如果处于单元格编辑模式,则取消单元格编辑。
如果处于字幕选择模式,则取消在行上的编辑。
ESC 键
当编辑单元格时,删除插入点前的字符。
BACKSPACE 键
当编辑单元格时,删除插入点后的字符。
DELETE 键
移动到当前行的第一个单元格。
HOME 键
移动到当前行的最后一个单元格。
END 键
突出显示当前单元格中的字符并将插入点置于该行的末尾。与双击单元格的行为相同。
F2 键
如果焦点在单元格上,则移动到该行中的下一个单元格。
如果焦点在某行中最后一个单元格上,则移动到该行的第一个子表链接并将其展开。
如果焦点在子链接上,则移动到下一个子链接。
如果焦点在最后一个子链接上,则移动到下一行的第一个单元格。
TAB 键
如果焦点在单元格上,则移动到该行中的上一个单元格。
如果焦点在某行中第一个单元格上,则移动到上一行中最后一个展开的子表链接,或移动到上一行中最后一个单元格。
如果焦点在子链接上,则移动到上一个子链接。
如果焦点在第一个子链接上,则移动到上一行的最后一个单元格。
SHIFT+TAB 键
按 Tab 键顺序移动到下一个控件。
CTRL+TAB 键
按 Tab 键顺序移动到上一个控件。
CTRL+SHIFT+TAB 键
如果在子表中,则向上移动到父表。与单击“后退”按钮的行为相同。
ALT+左箭头键
展开子表链接。ALT+下箭头键展开所有链接,而不仅仅是选定的链接。
ALT+下箭头键
或
CTRL+加号键
折叠子表链接。ALT+上箭头键折叠所有链接,而不仅仅是选定的链接。
ALT+上箭头键
或
CTRL+减号键
按箭头的方向移动到最远的一个非空单元格。
CTRL+箭头键
按箭头的方向将所选内容扩展一行(不包括子表链接)。
SHIFT+上/下箭头键
按箭头的方向将所选内容扩展到最远的一个非空行(不包括子表链接)。
CTRL+SHIFT+上/下箭头键
移动到左上角的单元格。
CTRL+HOME 键
移动到右下角的单元格。
CTRL+END 键
将所选内容扩展到顶端行。
CTRL+SHIFT+HOME 键
将所选内容扩展到底端行。
CTRL+SHIFT+END 键
选择当前行(不包括子表链接)。
SHIFT+SPACEBAR 键
选择整个网格(不包括子表链接)。
CTRL+A 键
当在子表中时,显示父行。
CTRL+PAGE DOWN 键
当在子表中时,隐藏父行。
CTRL+PAGE UP 键
将所选内容向下扩展一个屏幕(不包括子表链接)。
SHIFT+PAGE DOWN 键
将所选内容向上扩展一个屏幕(不包括子表链接)。
SHIFT+PAGE UP 键
为当前行调用 DataGrid.EndEdit 方法。
CTRL+ENTER 键
当处于编辑模式时,将 dbnull 值输入单元格。
CTRL+0 键
快捷键与菜单快捷方式被称为命令键,应用程序会在对常规输入进行处理前的消息预处理过程中对它们进行处理。命令键也就始终比常规输入键具有优先权。
ProcessCmdKey 方法首先确定控件是否有上下文菜单,如果有,则允许 ContextMenu 处理命令键。如果命令键不是菜单快捷方式,且控件有父级,那么该键传递到父级的 ProcessCmdKey 方法。净效果是命令键在控件层次结构中向上“冒”。除了用户按下的键外,键数据还指示哪些(如果有的话)修改键与该键同时按下。修改键包括 SHIFT、CTRL 和 ALT 键(成为组合键)。
这里要注意:该方法必须返回 true,以指示它已经处理完命令键,或者 false,以指示该键不是命令键。在派生类中重写 ProcessCmdKey 方法时,控件应返回 true 以指示它已处理该键。对于未由该控件处理的键,应返回调用基类的 ProcessCmdKey 方法的结果。
如果不加返回值,会默认为false。这样你明明已经修改了处理方法,却会在执行完你的命令之后,继续执行父类中定义的该键盘按键的处理方法。
那么我们怎么处理文头的命题?解决之道就是自己写一个控件,继承自现有的Datagrid控件,再重写处理命令键响应程序ProcessCmdKey,来实现我们的需求。
步骤一:在vs.net编辑器中,“文件”->“新建”->“项目”,然后选择新建一个“Windows控件库”的项目:HenryDatagrid。这样运行的结果会生成一个DLL文件,而不是EXE执行文件;
步骤二:在HenryDatagrid.vb文件代码编辑窗口中加入有阴影的这句话:
Public Class HenryDatagrid
Inherits System.Windows.Forms.DataGrid‘这表示新建的控件是Datagrid的派生控件
步骤三:在“类名”窗口中选择overrides,然后在“方法名称”窗口选择“ProcessCmdKey”(如图2所示)
图2 选择要重写的方法
然后就会出现一段空的ProcessCmdKey代码段,我们可以写入自己的代码:
Protected Overrides Function ProcessCmdKey(ByRef msg As System.Windows.Forms.Message, ByVal keyData As System.Windows.Forms.Keys) As Boolean
Dim WM_KEYDOWN As Integer = 256 ‘消息响应的问题可以参考其他win32编程的文章
Dim WM_SYSKEYDOWN As Integer = 260
If ((msg.Msg = WM_KEYDOWN) Or (msg.Msg = WM_SYSKEYDOWN)) Then
Select Case keyData
Case Keys.Down
MsgBox("截到下箭头键")
Return True
Case Keys.Up
MsgBox("截到上箭头键")
Return True
Case Keys.Enter
SendKeys.Send("{Tab}")
Return True
Case Keys.Control + Keys.M
MsgBox("<CTRL> + m 组合键被截获")
Return True
Case Keys.Alt + Keys.Z
MsgBox("<ALT> + z 组合键被截获")
Return True
End Select
End If
End Function
然后运行一下,生成HenryDatagrid.dll文件
步骤四:再建立一个项目,然后在新项目的设计窗口的工具箱上单击鼠标右键,在弹出菜单中选择“添加引用”,然后在.net选项卡中占击“浏览”,选择到HenryDatagrid.dll,加入进来,然后您的工具箱上会多出一个HenryDatagrid的图标,在新项目中使用HenryDatagrid来代替datagrid控件。看一下,您所需要的“Enter跳格”事件就这样完成了。
建议:您在Keys.Enter代码中的Return True去掉,看一下会有什么情况发生。
这里说句题外话,我们在重写类方法时,必须也只能使用Overridable关键字修饰的Protected
方法。这是因为在VB中是用Overridable 关键字指定属性或方法可以在派生类中重写。没有这个东东的我们也没有资格重写了。
-------------------------
声明:本文版权与解释权归韩睿所有,如需转载,请保留完整的内容及此声明。
QQ: 18349592
E-Mail: henry7685@hotmail.com
请访问本人专栏:http://www.csdn.net/develop/author/netauthor/Latitude/