近日在为一个数据应用写数据输入界面,大量的编辑框要想实现快速的输入就是有设计良好的符合工作流程的TAB键序。相信,不少的人在使用具有大量编辑框的程序时都有这样的想法和感概。而我这个对话框界面主要输入的是数字,因此如果使用TAB键作编辑框之间的跳转会在使用数字键盘时不方便。因此,就考虑了用回车键来实现TAB键的功能。因为MFC对话框的特点,基于MFC对话框的对话框按下回车键会调用框架内的的OnOk成员函数导至退出。即使你去掉IDC_OK按键的BS_DEFPUSHBUTTON 属性也是不行的。
必须重载WM_GETDEFID,因为当用户按下回车键时,Windows发送WM_GETDEFID消息来获得缺省的命令ID,Windows再将它作为WM_COMMAND发送,所以重载这个消息必须在高位字中返回DC_HASDEFID。 如下所例:
BEGIN_MESSAGE_MAP(CMyDlg, CDialog)
ON_MESSAGE(DM_GETDEFID, OnGetDefID)
...
END_MESSAGE_MAP()
LRESULT CMyDlg::OnGetDefID(WPARAM wp, LPARAM lp)
{
return MAKELONG(0,DC_HASDEFID);
}
这是一种方法,另外一种方法是在消息循环处着手处理。重载PreTranslateMessage这个虚函数,将消息队列中有关键盘按下的消息给拦载下来,在框架之前处理WM_KEYDOWN消息。判断是按下回车键后,我们可以用GetNextDlgTabItem 函数获得TAB键序中下一个或上一个接受TAB键的控件句柄。示例代码如下:
BOOL CKeydownDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
{
CWnd *mwnd = GetNextDlgTabItem (GetFocus()); //取得当前焦点控件的下一个控件的句柄
if (mwnd)
{
mwnd->SetFocus(); //设置下一件控件得到输入焦点
return TRUE;
}
}
return CDialog::PreTranslateMessage(pMsg);
}
但是,各位有没有注意到。这样处理之后,虽然可以在各个控件之进行输入焦点的转移。可是当一个按钮控件获得了焦点之后,也是按下回车键。以前我们习惯中或者说预料中按下该按钮的后应该执行的功能没有被执行,而焦点又跑到按钮之后的控件上去了。这就是上面代码的不足之处,虽然实现了焦点由回车键控件转移,但是按钮却不能用回车键来操作了。只以用鼠标,这和大家习惯不合。而且,在快速的数据输入中不能用回车键来按下这个按钮却要用鼠标来点击也有违当初我们要快速这样一个目的。所以,还得对以上代码做适当的修改。代码如下。
在这里增加了对当前焦点控件类的判断,即如果当前控件是按钮(Button)那么就不执行焦点跳转而是构造一条WM_COMMAND消息发送给程序,让程序以为是鼠标点击了该按钮。从而执行了这个按钮具有的功能而不是什么也不做的焦点转移。
BOOL CKeydownDlg::PreTranslateMessage(MSG* pMsg)
{
if (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_RETURN)
{
CWnd *wnd = GetFocus ();
if (wnd != NULL)
{
char str[256];
CString ClassName = _T("Button");
GetClassName (wnd->m_hWnd, str, 256);
if (ClassName == str)
{
UINT i = wnd->GetDlgCtrlID ();
SendMessage (WM_COMMAND, i, (LPARAM)wnd->m_hWnd);
return TRUE;
}
}
CWnd *mwnd = GetNextDlgTabItem (wnd);
if (mwnd)
{
mwnd->SetFocus();
return TRUE;
}
}
return CDialog::PreTranslateMessage(pMsg);
}