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); } |
while (GetMessage(...)) { TranslateMessage(...); DispatchMessage(...); } |
while (GetMessage(...)) { if (TranslateAccelerator(hAccel...)) { // handled, continue looping } else { TranslateMessage(...); DispatchMessage(...); } } |
// 简化后的 CWinThread while (GetMessage(...)) { if (PreTranslateMessage(...)) { // continue looping } else { TranslateMessage(...); DispatchMessage(...); } } |
BOOL CFrameWnd::PreTranslateMessage(MSG* pMsg) { ...... if (pMsg->message >= WM_KEYFIRST && pMsg->message <= WM_KEYLAST) { ::TranslateAccelerator(m_hAccelTable,...); } } |
BOOL CMyDlg::OnInitDialog() { CDialog::OnInitDialog(); ...... // Load accelerators m_hAccel = ::LoadAccelerators(AfxGetResourceHandle(), m_lpszTemplateName); ASSERT(m_hAccel); return TRUE; } |
// 本文例子中的加速键(In DlgKeys.rc ) IDD_MYDIALOG ACCELERATORS DISCARDABLE BEGIN VK_RETURN, ID_MY_ENTER, VIRTKEY, NOINVERT END |
BOOL CMyDlg::PreTranslateMessage(MSG* pMsg) { if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST) { HACCEL hAccel = m_hAccel; if (hAccel && ::TranslateAccelerator(m_hWnd, hAccel, pMsg)) return TRUE; } return CDialog::PreTranslateMessage(pMsg); } |
之所以要检查按键类的消息(从WM_ KEYFIRST 到 WM_KEYLAST)是为了提高速度。如果你知道不是一个按键消息,你就不用浪费时间去调用TranslateAccelerator()。再说TranslateAccelerator()是一个虚拟函数,不用增加一个消息映射入口。仅仅写这个函数就可以了。
二、编程步骤
1、 启动Visual C++6.0,生成一个Win32应用程序,将该程序命名为"DlgKeys";
2、 使用CLASSWIZARD为应用程序添加CdlgWithAccelerators和CmyDlg类;
3、 在程序的资源中添加添加加速键资源,内容如下:ID_MY_ENTER, VK_RETURNVIRTKEY,VIRTKEY;
4、添加代码,编译运行程序。
三、程序代码
///////////////////////////////////////// #include "stdafx.h" // Generic dialog-that-uses-accelerators. class CDlgWithAccelerators : public CDialog { public: CDlgWithAccelerators(UINT nIDTemplate, CWnd* pParentWnd = NULL); CDlgWithAccelerators(LPCTSTR lpszTemplateName, CWnd* pParentWnd = NULL); ~CDlgWithAccelerators(); protected: HACCEL m_hAccel; // accelerator table // MFC overrides virtual BOOL OnInitDialog(); virtual BOOL PreTranslateMessage(MSG* pMsg); DECLARE_MESSAGE_MAP() }; /////////////////////////////////////////// // CDlgWithAccelerators is a general-purpose class that adds accelerators to CDialog. #include "stdafx.h" #include "dlgaccel.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif BEGIN_MESSAGE_MAP(CDlgWithAccelerators,CDialog) END_MESSAGE_MAP() CDlgWithAccelerators::CDlgWithAccelerators(LPCTSTR lpszTemplateName, CWnd* pParentWnd) : CDialog(lpszTemplateName, pParentWnd) {} CDlgWithAccelerators::CDlgWithAccelerators(UINT nIDTemplate, CWnd* pParentWnd) : CDialog(nIDTemplate, pParentWnd) {} CDlgWithAccelerators::~CDlgWithAccelerators() {} /////////////////////////// Pre-translate message: translate keystrokes using acclerator table. BOOL CDlgWithAccelerators::PreTranslateMessage(MSG* pMsg) { if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST) { HACCEL hAccel = m_hAccel; if (hAccel && ::TranslateAccelerator(m_hWnd, hAccel, pMsg)) return TRUE; } return CDialog::PreTranslateMessage(pMsg); } //////////////////// Initialize dialog: load accelerators BOOL CDlgWithAccelerators::OnInitDialog() { BOOL bRet = CDialog::OnInitDialog(); // Load dialog@#s accelerators m_hAccel = ::LoadAccelerators(AfxGetResourceHandle(), m_lpszTemplateName); // use same resource name as dialog return bRet; } ///////////////////////////////////////////////////////////////////////// #include "stdafx.h" #include "resource.h" #include "dlgaccel.h" #include "TraceWin.h" #ifdef _DEBUG #define new DEBUG_NEW #undef THIS_FILE static char THIS_FILE[] = __FILE__; #endif /////////////MFC app class CMyApp : public CWinApp { public: CMyApp(); ~CMyApp(); virtual BOOL InitInstance(); DECLARE_MESSAGE_MAP() }; CMyApp theApp; // THE one-and-only app //////////// frame window class CMainFrame : public CFrameWnd { protected: virtual BOOL PreCreateWindow(CREATESTRUCT& cs); public: CMainFrame(); ~CMainFrame(); }; //////////////////// Typical dialog class CMyDlg : public CDlgWithAccelerators { public: CMyDlg(CWnd* pParent = NULL); // standard constructor protected: HICON m_hIcon; void NextInTabOrder(); // MFC overrides virtual BOOL OnInitDialog(); afx_msg void OnMyEnter(); afx_msg LRESULT OnGetDefID(WPARAM wp, LPARAM lp); DECLARE_MESSAGE_MAP() }; BEGIN_MESSAGE_MAP(CMyApp, CWinApp) END_MESSAGE_MAP() CMyApp::CMyApp() { // nothing to do } CMyApp::~CMyApp() { // nothing to do } //////////////////// InitInstance: create dialog as child BOOL CMyApp::InitInstance() { // create frame window and load it CMainFrame* pFrame = new CMainFrame; m_pMainWnd = pFrame; pFrame->LoadFrame(IDR_MAINFRAME, WS_OVERLAPPED, NULL, NULL); CMyDlg dlg(pFrame); // create dialog and run it int nResponse = dlg.DoModal(); if (nResponse == IDOK) {} else if (nResponse == IDCANCEL) {} return FALSE; // quit } CMainFrame::CMainFrame() { // nothing to do } CMainFrame::~CMainFrame() { // nothing to do } ///////////// Pre-create window: set WS_EX_TOOLWINDOW style to hide dialog from task bar BOOL CMainFrame::PreCreateWindow(CREATESTRUCT& cs) { if (CFrameWnd::PreCreateWindow(cs)) { cs.dwExStyle |= WS_EX_TOOLWINDOW; return TRUE; } return FALSE; } BEGIN_MESSAGE_MAP(CMyDlg, CDlgWithAccelerators) ON_COMMAND(ID_MY_ENTER, OnMyEnter) // The following is NOT needed since I am using accelerators to map // ENTER to ID_MY_ENTER. But if all you want to do is ignore the Enter key, // you can handle DM_GETDEFID as below. // ON_MESSAGE(DM_GETDEFID, OnGetDefID) // not used END_MESSAGE_MAP() CMyDlg::CMyDlg(CWnd* pParent) : CDlgWithAccelerators(IDD_MYDIALOG, pParent) {} //////////////////// Initialize dialog: BOOL CMyDlg::OnInitDialog() { CDlgWithAccelerators::OnInitDialog(); // Set the icon for this dialog. The framework does this automatically // when the application@#s main window is not a dialog m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); ASSERT(m_hIcon); SetIcon(m_hIcon, TRUE); // Set big icon SetIcon(m_hIcon, FALSE); // Set small icon // use same resource name as dialog to load dialog@#s accelerators m_hAccel = ::LoadAccelerators(AfxGetResourceHandle(),m_lpszTemplateName); ASSERT(m_hAccel); return TRUE; // return TRUE unless you set the focus to a control } //////////////////// This is called to handle ID_MY_ENTER--ie, Enter key. void CMyDlg::OnMyEnter() { TRACE(_T("CMyDlg::OnMyEnter\n")); NextInTabOrder(); // move to next control } //////////////////// Helper function to move focus to the next control. void CMyDlg::NextInTabOrder() { CWnd* pWndNext = GetNextDlgTabItem(GetFocus()); if (pWndNext) { pWndNext->SetFocus(); } } ////////////////// // This function is not used, since its message map entry is commented out. // If all you want to do is ignore the Enter key (not map it to a command), // then all you have to do is return zero here. Note that you MUST return // the special code DC_HASDEFID in the high-order word!! LRESULT CMyDlg::OnGetDefID(WPARAM wp, LPARAM lp) { TRACE(_T("CMyDlg::OnGetDefID\n")); return MAKELONG(0,DC_HASDEFID); } |