MFC中临时禁用快捷键的方法

来源:互联网 发布:淘宝网页登录页面 编辑:程序博客网 时间:2024/05/13 09:01

本人使用C++编程已有很多年,遇到过也解决过太多太多的问题,虽不敢说是编程高手,但也有很多编程经验。由于自己太懒,没有做笔记的习惯,导致很多时候还得花大把时间解决以前解决过的问题。今天终于决定把自己这些年编程的经验以及遇到的一些问题及解决办法记录下来。今天先把今天刚解决的问题写出来,以后再慢慢把想到的东西补上。

相信有童鞋做过简单的资源管理器,显示计算机中的文件和文件夹(以下统称文件),并提供对文件的删除和重命名等功能(为什么一定要提到删除和重命名呢,便于下面的举例罢了)。如果为删除命令添加快捷键,即Delete键,在重命名时,您选择一部分文字,想把它删除再重新键入,按下Delete键,你会很惊讶地发现,文件被删除了,而不是文字被删除,如下图:

显然,MFC把Delete当成快捷键处理了,那么为什么呢,我们可以重写视图类和框架类的PreTranslateMessage函数,用AfxMessageBox来显示不同的信息,看是谁先处理或者是谁处理了这个按键消息,结果发现视图类没有处理这一消息,是由框架类处理的,这就好办了,框架类继承自CFrameWnd类,还好,微软还算厚道,提供了MFC源代码,打开winfrm.cpp,找到CFrameWnd::PreTranslateMessage函数,如下:

BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg){ENSURE_ARG(pMsg != NULL);// check for special cancel modes for combo boxesif (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_NCLBUTTONDOWN)AfxCancelModes(pMsg->hwnd);    // filter clicks// check for key strokes that may affect the menu bar stateif ((m_dwMenuBarVisibility & AFX_MBV_DISPLAYONF10) && pMsg->message == WM_SYSKEYUP && pMsg->wParam == VK_F10){SetMenuBarState(AFX_MBS_VISIBLE);}if (m_dwMenuBarVisibility & AFX_MBV_DISPLAYONFOCUS){if (pMsg->message == WM_SYSKEYUP &&pMsg->wParam == VK_MENU){SetMenuBarState(m_dwMenuBarState == AFX_MBS_VISIBLE ? AFX_MBS_HIDDEN : AFX_MBS_VISIBLE);}else if (pMsg->message == WM_SYSCHAR &&m_dwMenuBarState == AFX_MBS_HIDDEN){// temporarily show the menu bar to enable menu access keysSetMenuBarState(AFX_MBS_VISIBLE);m_bTempShowMenu = TRUE;}}if ((m_dwMenuBarVisibility & AFX_MBV_KEEPVISIBLE) == 0){if ( (pMsg->message == WM_KEYDOWN && pMsg->wParam == VK_ESCAPE) || (pMsg->message == WM_LBUTTONDOWN || pMsg->message == WM_RBUTTONDOWN) ||((pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCRBUTTONDOWN) && pMsg->wParam != HTMENU)){SetMenuBarState(AFX_MBS_HIDDEN);}}if (pMsg->message == WM_NCLBUTTONDOWN || pMsg->message == WM_NCRBUTTONDOWN){m_bMouseHitMenu = (pMsg->wParam == HTMENU);}else if (pMsg->message == WM_NCLBUTTONUP || pMsg->message == WM_NCRBUTTONUP ||pMsg->message == WM_LBUTTONUP || pMsg->message == WM_RBUTTONUP){m_bMouseHitMenu = FALSE;}// allow tooltip messages to be filteredif (CWnd::PreTranslateMessage(pMsg))return TRUE;#ifndef _AFX_NO_OLE_SUPPORT// allow hook to consume messageif (m_pNotifyHook != NULL && m_pNotifyHook->OnPreTranslateMessage(pMsg))return TRUE;#endifif (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST){// finally, translate the messageHACCEL hAccel = GetDefaultAccelerator();return hAccel != NULL &&  ::TranslateAccelerator(m_hWnd, hAccel, pMsg);}return FALSE;}

 

看到高亮的部分了吧,不是没有被处理,只不过CWnd没有转换消息而已,结果CFrameWnd强制匹配快捷键,所以按Delete键实际上达到了删除文字的目的,只不过还没来得及看到删除结果的时候,文件已经被删了。

 

知道原理了就好办了,下面是解决办法:

1. 在CMainFrame类中添加一个BOOL类型的成员变量,不妨取名为m_bEnableAccelerator,初始化为FALSE;

2. 在CMainFrame类中添加一个public的函数原型为void EnableAccelerator(BOOL Enable = TRUE)。实现很简单,只有一句话:m_bEnableAccelerator = Enable;

3. 在CMainFrame类中重写PreTranslateMessage函数,代码如下:

BOOL CMainFrame::PreTranslateMessage(MSG* pMsg){// TODO: 在此添加专用代码和/或调用基类if (!m_bEnableAccelerator) {//// 对于所有的按键消息// 如果已经禁用了快捷键,此时进行了按键操作,则绕过// CFrameWnd的消息处理,直接使用CWnd处理按键消息//if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) {return CWnd::PreTranslateMessage(pMsg);}}return CFrameWnd::PreTranslateMessage(pMsg);}


好了,在CListView类中,添加LVN_BEGINLABELEDIT和LVN_ENDLABELEDIT的消息处理函数,前者在开始编辑标签时产生,后者在结束编辑时产生,很显然,在前者的处理函数中调用CMainFrame中的EnableAccelerator即可,前者参数传FALSE,后者传入TRUE即可,代码如下:

NMLVDISPINFO *pDispInfo = reinterpret_cast<NMLVDISPINFO*>(pNMHDR);// TODO: 在此添加控件通知处理程序代码CMainFrame *pMainFrame = (CMainFrame *) AfxGetMainWnd();pMainFrame->EnableAccelerator(FALSE); // EndLabelEdit中传入TRUE或不传参数即可*pResult = 0;