如何定制对话框中的回车键?
基于对话框的程序中,每次按下回车键时,程序都退出。去掉按钮的 BS_DEFPUSHBUTTON 属性并重写OnOK函数也没用。那么如何定制回车键的行为呢?这个问题很easy,但是要说明白,却要费点时间。
这个问题在Windows的开发中由来已久,对于初学者来说,这是个恼人的问题,幸运的是,人们找到了多种解决这个问题的方案。本文将告诉你定制回车键行为的方法。
如果你想要disable回车键,最简单的方法是重载OnOK函数,这固然是个不坏的主意,但如果你重载OnOK,让它什么事情也不干,那麽当用户用鼠标按下回车键想真正做些什么的时候怎么办呢?你可以改变回车键的ID,如:ID_MY_OK,并写一个调用EndDialog的处理器,这个方法虽然也能行得通,但显得有点不专业。
另外一种方法是disable回车键的“默认”属性。这也是本文开始所提出的方法,之所以没有成功,是因为仅仅uncheck 回车键的 BS_DEFPUSHBUTTON 属性是不够的,你可以利用Spy++仔细地观察控制和实验就能发现回车键仍然我行我素发送退出消息。
问题出在哪呢?你必须区分OK键和回车键,你可以写一个OnOK处理器调用GetCurrentMessage函数获取最后发送的消息,应该是WM_COMMAND,再检查WPARAM的低位字(low-order word)看看命令来自何处。
要解决问题,必须搞清楚背后所发生的一切,在Spy++中可以看到,当用户按下回车键时,Windows发送一个特殊的WM_GETDEFID消息来获得缺省的命令ID,Windows再将它作为WM_COMMAND发送。所以,你要做的就是重载WM_GETDEFID消息,在有关Windows的文档中是这样描述WM_GETDEFID返回值的:“如果有缺省得按钮,则返回值的高位字包含DC_HASDEFID,低位字包含控制的标识符。否则,返回值是零。”
根据这段描述,假设如果没有缺省得按钮,则返回值应该是零。如果想要disable缺省得ID,必须在高位字中返回DC_HASDEFID。
01.BEGIN_MESSAGE_MAP(CMyDlg, CDialog)02.ON_MESSAGE(DM_GETDEFID, OnGetDefID)03....04.END_MESSAGE_MAP()05. 06.LRESULT CMyDlg::OnGetDefID(WPARAM wp, LPARAM lp) 07.{08.return MAKELONG(0,DC_HASDEFID); 09.}01.BEGIN_MESSAGE_MAP(CMyDlg, CDialog) 02.ON_COMMAND(ID_MY_ENTER, OnMyEnter)03.......04.END_MESSAGE_MAP() 05. 06.void CMyDlg::OnMyEnter() 07.{08.NextInTabOrder(); 09.}1.while (GetMessage(...)) { 2.TranslateMessage(...);3.DispatchMessage(...); 4.}1.while (GetMessage(...)) { 2.if (TranslateAccelerator(hAccel...)) { 3.// handled, continue looping 4.} else { 5.TranslateMessage(...); 6.DispatchMessage(...); 7.} 8.}01.// 简化后的 CWinThread 02.while (GetMessage(...)) { 03.if (PreTranslateMessage(...)) { 04.// continue looping 05.} else { 06.TranslateMessage(...); 07.DispatchMessage(...); 08.}09.}
01.BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg) 02.{ 03.......04.if (pMsg->message >= WM_KEYFIRST && 05.pMsg->message <= WM_KEYLAST) 06.{ 07.::TranslateAccelerator(m_hAccelTable,...); 08.} 09.}01.BOOL CMyDlg::OnInitDialog() 02.{ 03.CDialog::OnInitDialog(); 04.......05.// Load accelerators 06.m_hAccel = ::LoadAccelerators(AfxGetResourceHandle(), 07.m_lpszTemplateName); 08.ASSERT(m_hAccel); 09. 10.return TRUE; 11.}1.// 本文例子中的加速键(In DlgKeys.rc )2.IDD_MYDIALOG ACCELERATORS DISCARDABLE 3.BEGIN 4.VK_RETURN, ID_MY_ENTER, VIRTKEY, NOINVERT 5.END
01.BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) 02.{ 03.if (WM_KEYFIRST <= pMsg->message && 04.pMsg->message <= WM_KEYLAST) 05.{ 06.HACCEL hAccel = m_hAccel; 07.if (hAccel && 08.::TranslateAccelerator(m_hWnd, hAccel, pMsg)) 09.return TRUE; 10.} 11.return CDialog::PreTranslateMessage(pMsg); 12.}