版權(quán)說明:本文檔由用戶提供并上傳,收益歸屬內(nèi)容提供方,若內(nèi)容存在侵權(quán),請進(jìn)行舉報或認(rèn)領(lǐng)
文檔簡介
1、VC程序開發(fā)中定制對話框中的回車鍵基于對話框的程序中,每當(dāng)用戶按下回車鍵時,程序都會退出,其效果和按下對話框中的默認(rèn)OK按鈕是一樣的,即使去掉OK按鈕的 BS_DEFPUSHBUTTON 屬性也沒用。那么如何定制回車鍵的行為呢?這個問題在Windows的開發(fā)中由來已久,對于初學(xué)者來說,這是個惱人的問題,幸運(yùn)的是,人們找到了很多種解決這個問題的方案。本實(shí)例將告訴你實(shí)現(xiàn)定制回車鍵行為的方法。一、實(shí)現(xiàn)方法如果想要使回車鍵無效,最簡單的方法是重載OnOK()函數(shù),這固然是個不壞的主意,但如果重載OnOK()函數(shù),讓它什么事情也不干,那么當(dāng)用戶用鼠標(biāo)按下OK按鈕想真正做些什么的時候怎么辦呢?你可以改變回
2、車鍵的ID,如:ID_MY_OK,并寫一個調(diào)用EndDialog()的處理器,這個方法雖然也能行得通,但顯得有點(diǎn)不專業(yè)。另外一種方法是disable回車鍵的默認(rèn)屬性。這也是本文開始所提出的方法,之所以沒有成功,是因為僅僅不設(shè)置OK按鈕的BS_DEFPUSHBUTTON 屬性是不夠的,可以利用Visual C+中的Spy+工具仔細(xì)地觀察,就能發(fā)現(xiàn)回車鍵仍然我行我素發(fā)送退出消息。問題出在哪呢?你必須區(qū)分OK按鈕和回車鍵,你可以寫一個OnOK處理器調(diào)用GetCurrentMessage()函數(shù)獲取最后發(fā)送的消息,應(yīng)該是WM_COMMAND,再檢查WPARAM的低位字(low-order word)看
3、看命令來自何處。要解決問題,必須搞清楚背后所發(fā)生的一切,在Spy+中可以看到,當(dāng)用戶按下回車鍵時,Windows發(fā)送一個特殊的WM_GETDEFID消息來獲得缺省的命令I(lǐng)D,Windows再將它作為WM_COMMAND發(fā)送。所以,我們要做的就是重載WM_GETDEFID消息。在有關(guān)Windows的文檔中是這樣描述WM_GETDEFID返回值的:如果有缺省的按鈕,則返回值的高位字包含DC_HASDEFID,低位字包含控制的標(biāo)識符。否則,返回值是零。根據(jù)這段描述,假設(shè)如果沒有缺省得按鈕,則返回值應(yīng)該是零。如果想要disable缺省得ID,必須在高位字中返回DC_HASDEFID,為此定義和實(shí)現(xiàn)消息
4、映射函數(shù)如下: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); 因為MFC沒有對應(yīng)DM_GETDEFID的宏,你必須使用通用的ON_MASSAGE宏。這樣用戶可以隨意按回車鍵,但什么事都不會發(fā)生。上面的做法是解決了按回車鍵程序退出的問題,但是又產(chǎn)生了另外一個問題:如果想要回車鍵做些事情怎么辦呢?有一些人曾經(jīng)問過如
5、何將回車鍵映射到TAB鍵,既按下回車鍵就象按下TAB鍵一樣,也就是說輸入焦點(diǎn)移動到下一個對話框控制。這需要做一些工作才行,但最簡單的方式是使用加速鍵。許多程序員試圖用OnChar()響應(yīng)函數(shù),但它是一個低級趣味的東西,應(yīng)該想方設(shè)法盡量避免使用它,更糟的還有WM_KEYDOWN,WM_KEYUP之類的消息。誰能處理這些消息呢?OnChar()可以用來限制允許輸入編輯框的字符,如:數(shù)字,字母等。如果想要將一個鍵映射到一個命令,加速鍵才是最好的方法。在本實(shí)例中為VK_RETURN創(chuàng)建了一個加速鍵,將它映射到命令I(lǐng)D_MY_ENTER,并寫一個命令處理器來實(shí)現(xiàn)任何想實(shí)現(xiàn)的事情。如果你細(xì)心的話會發(fā)現(xiàn)另外
6、一個還沒有得到解決的問題,那就是在MFC對話框不自動處理加速鍵,你必須自己編寫代碼來做這件事情。為了理解弄清楚這是為什么,讓我們回首Windows開發(fā)的歷程,在使用C和原始的Windows API的年代,每一個Windows程序中都有一個叫做消息泵的中樞循環(huán):while (GetMessage(.) TranslateMessage(.);DispatchMessage(.); 在這里細(xì)節(jié)不是最重要的,最重要的是消息并不到達(dá)程序的流程,你必須請求消息。這是一種人為的非搶先式多任務(wù)方法,這種方法通過每一個任務(wù)精誠協(xié)作來仿造多任務(wù)環(huán)境,隨著增加的功能越來越多,有人想到了加速鍵表的主意,這個表用來映
7、射按鍵和命令I(lǐng)Ds。為了實(shí)現(xiàn)這個目的,微軟發(fā)明了一個叫TranslateAccelerator()的函數(shù)。現(xiàn)在這個消息泵變成了如下的樣子:while (GetMessage(.) if (TranslateAccelerator(hAccel.) / handled, continue looping else TranslateMessage(.); DispatchMessage(.); hAccel是個加速鍵表句柄,在這里細(xì)節(jié)同樣不是重要的,重要的是如何利用加速鍵表,也就是要有一個專門的函數(shù)將按鍵消息解釋為WM_COMMAND消息。TranslateAccelerator()函數(shù)尋找WM
8、_KEYDOWN,WM_CHAR,WM_KEYUP序列與表中鍵值匹配的字符。如果找到,它插入一條WM_COMMAND到消息隊列,在消息隊列中的命令I(lǐng)D可以是加速鍵表定義的任何入口。這樣你只要設(shè)置加速鍵表(在資源中)并記住調(diào)用對應(yīng)的函數(shù)TranslateAccelerator(),就什么都不用擔(dān)心了。隨著Visual C+和MFC的日臻成熟,現(xiàn)在幾乎整個消息循環(huán)(但不是全部)都被隱藏到了MFC中,為了能讓任何窗口都有機(jī)會獲得一點(diǎn)消息泵的行為,MFC提供了一個專門的虛函數(shù)PreTranslateMessage(),如果你有足夠的勇氣去探究CWinThread中的消息處理機(jī)制的話,你會遇到類似如下的
9、代碼:/ 簡化后的 CWinThread while (GetMessage(.) if (PreTranslateMessage(.) / continue looping else TranslateMessage(.); DispatchMessage(.); CWinThread:PreTranslateMessage()是個虛函數(shù),在應(yīng)用中,其缺省的實(shí)現(xiàn)以相同的名字調(diào)用另一個虛函數(shù)CWnd:PreTranslateMessage()。因此,如果需要在消息循環(huán)中做些什么的話,如解釋加速鍵,只要重載PreTranslateMessage()函數(shù)即可。實(shí)際上,這就是程序的框架CFrameW
10、nd類處理加速鍵的方法。BOOL CFrameWnd:PreTranslateMessage(MSG* pMsg) .if (pMsg-message = WM_KEYFIRST & pMsg-message = WM_KEYLAST) :TranslateAccelerator(m_hAccelTable,.); CFrameWnd類是從哪里獲得加速鍵表呢?當(dāng)加載框架時,CFrameWnd:LoadFrame()函數(shù)使用與文檔模板相同的ID(如IDR_MAINFRAME)查找加速鍵表,并將它加載到m_hAccelTable變量中。所有的處理細(xì)節(jié)在MFC中都是自動的、隱蔽的,讀者朋友不用去操心
11、。但是上述內(nèi)容僅僅是對主框架而言,如果是對話框,則是另外一種情況,因為CDialog不是從CFrameWnd派生而來,所以不繼承任何有關(guān)加速鍵的內(nèi)容。對于這個問題不用擔(dān)心,我們可以模仿CFrameWnd的工作,很容易為對話框增加加速鍵的功能。第一步是加載加速鍵,加載加速鍵最好的地方是在對話框的OnInitDialog函數(shù)中:=金牌站長站=BOOL CMyDlg:OnInitDialog() CDialog:OnInitDialog(); ./ Load accelerators m_hAccel = :LoadAccelerators(AfxGetResourceHandle(), m_lps
12、zTemplateName); ASSERT(m_hAccel); return TRUE; 在加速鍵表中,可以使用任何ID。例如上面的代碼使用的是對話框本身的ID,(m_lpszTemplateName既可以是一個串名,也可以是一個MAKEINTRESOURCE使用的整型ID)。/ 本文例子中的加速鍵(In DlgKeys.rc )IDD_MYDIALOG ACCELERATORS DISCARDABLE BEGIN VK_RETURN, ID_MY_ENTER, VIRTKEY, NOINVERT END 一旦已經(jīng)加載加速鍵,剩下的事情是重載PreTranslateMessage函數(shù),進(jìn)行
13、消息映射了:BOOL CMyDlg:PreTranslateMessage(MSG* pMsg) if (WM_KEYFIRST 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)是為了提高速度。如果你知道不是一個按鍵消
14、息,你就不用浪費(fèi)時間去調(diào)用TranslateAccelerator()。再說TranslateAccelerator()是一個虛擬函數(shù),不用增加一個消息映射入口。僅僅寫這個函數(shù)就可以了。二、編程步驟1、 啟動Visual C+6.0,生成一個Win32應(yīng)用程序,將該程序命名為DlgKeys;2、 使用CLASSWIZARD為應(yīng)用程序添加CdlgWithAccelerators和CmyDlg類; 3、 在程序的資源中添加添加加速鍵資源,內(nèi)容如下:ID_MY_ENTER, VK_RETURNVIRTKEY,VIRTKEY;4、添加代碼,編譯運(yùn)行程序。三、程序代碼/#include stdafx.h
15、/ 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/ MF
16、C overridesvirtual 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_FILEstatic char THIS_FILE = _
17、FILE_;#endifBEGIN_MESSAGE_MAP(CDlgWithAccelerators,CDialog)END_MESSAGE_MAP()CDlgWithAccelerators:CDlgWithAccelerators(LPCTSTR lpszTemplateName, CWnd* pParentWnd) : CDialog(lpszTemplateName, pParentWnd)CDlgWithAccelerators:CDlgWithAccelerators(UINT nIDTemplate,CWnd* pParentWnd) : CDialog(nIDTemplate,
18、 pParentWnd)CDlgWithAccelerators:CDlgWithAccelerators()/ Pre-translate message: translate keystrokes using acclerator table. BOOL CDlgWithAccelerators:PreTranslateMessage(MSG* pMsg)if (WM_KEYFIRST message & pMsg-message LoadFrame(IDR_MAINFRAME, WS_OVERLAPPED, NULL, NULL);CMyDlg dlg(pFrame); / create
19、 dialog and run itint nResponse = dlg.DoModal();if (nResponse = IDOK)else if (nResponse = IDCANCEL)return FALSE; / quitCMainFrame:CMainFrame()/ nothing to doCMainFrame:CMainFrame()/ nothing to do/ Pre-create window: set WS_EX_TOOLWINDOW style to hide dialog from task barBOOL CMainFrame:PreCreateWind
20、ow(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 wa
21、nt to do is ignore the Enter key,/ you can handle DM_GETDEFID as below./ ON_MESSAGE(DM_GETDEFID, OnGetDefID) / not usedEND_MESSAGE_MAP()CMyDlg:CMyDlg(CWnd* pParent) : CDlgWithAccelerators(IDD_MYDIALOG, pParent)/ Initialize dialog:BOOL CMyDlg:OnInitDialog()CDlgWithAccelerators:OnInitDialog();/ Set th
22、e icon for this dialog. The framework does this automatically/ when the applications main window is not a dialogm_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);ASSERT(m_hIcon);SetIcon(m_hIcon, TRUE); / Set big iconSetIcon(m_hIcon, FALSE); / Set small icon/ use same resource name as dialog to load dial
23、ogs acceleratorsm_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:OnMyEntern);NextInTabOrder(); / move to
24、 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 ke
25、y (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:OnGetDefIDn);return MAKELONG(0,DC_HASDEFID); 四、小結(jié)綜上所述,MFC中為對話框添加加速鍵功能的方法就是:加載加速鍵和重載
26、PreTranslateMessage()函數(shù)。也就是說,如果開發(fā)人員決定在對話框中使用加速鍵,不用去操心OnGetDefID()函數(shù)的處理,而是要重點(diǎn)實(shí)現(xiàn)加速鍵對應(yīng)的WM_COMMAND消息響應(yīng)處理函數(shù)。摘要 :本文講述了在指定的編輯框上能響應(yīng)從鍵盤輸入回車鍵的一種方法,對進(jìn)程內(nèi)消息的解析、動態(tài)獲取指定資源ID等技術(shù)也作了簡要描述。 關(guān)鍵字 :Microsoft Visual C+ 6.0、編輯框、回車鍵、消息、資源 一、引言 在通常的以CEditView為基類的單文檔/多文檔視圖程序中,可以很好的響應(yīng)鍵盤輸入的回車鍵,只需比較最近兩次的輸入的字符,看看最新輸入的字符是否內(nèi)碼是13(0x0d
27、,回車鍵的內(nèi)碼)即可識別出來,而要單獨(dú)把一個編輯框放入對話框中卻根本不響應(yīng),這個看似簡單的問題在實(shí)際應(yīng)用中還是解決起來比較困難的。尤其是當(dāng)一個充當(dāng)表單錄入的對話框上有若干個編輯框,這就要求在一個編輯框添完一項表單后用習(xí)慣的回車鍵將該編輯框上的數(shù)據(jù)讀取到內(nèi)存中去,并自動將光標(biāo)移動到下一個編輯框中準(zhǔn)備填寫下一欄表單。無疑這種界面是十分人機(jī)友好的,使錄入人員不必去執(zhí)行每填一下表單就去按一下執(zhí)行讀入到緩存功能的按鈕的煩瑣操作。但上述功能的實(shí)現(xiàn)卻并不象其演示的功能那樣簡單,下面本文就對這項技術(shù)的實(shí)現(xiàn)及附帶的其他技術(shù)作簡要的介紹。 二、不能響應(yīng)回車鍵的原因分析 之所以在以CEditView作為基類的程序中
28、可以響應(yīng)回車鍵,是由于該程序的視類本身就是一個Edit控件,這就是問題的關(guān)鍵所在。CEditView作為CView的派生類能響應(yīng)從鍵盤輸入的各種消息,其中有和鍵盤輸入相關(guān)的WM_CHAR、WM_KEYDOWN、WM_KEYUP等消息。我們就可以在這些消息的響應(yīng)函數(shù)中靈活地設(shè)計程序去捕捉到回車鍵的輸入,并執(zhí)行響應(yīng)的操作。 當(dāng)我們將編輯框作為一個普通的控件放到對話框上時情況就發(fā)生了變化。在此我們以CFormView為例,它也是CView的一個派生類,視是一個Form窗體(即對話框),當(dāng)放有編輯框的窗體有回車鍵輸入時,由于只有編輯框可以接受從鍵盤輸入的字符,所以當(dāng)鍵盤按下時統(tǒng)統(tǒng)把消息都發(fā)給了編輯框(
29、在Windows下每個窗口、按鈕、編輯框都看作一個窗口,都可以接受消息),可以通過ClassWizard在Object IDs選中編輯框所對應(yīng)的ID號,在右邊的消息框中可以看出該編輯框并不能響應(yīng)WM_CHAR等消息,只能用EN_CHANGE事件來做類似的響應(yīng)??僧?dāng)我們加入了對該事件的處理函數(shù)時,卻又將回車鍵當(dāng)作控制字符,當(dāng)輸入回車鍵并不會激發(fā)EN_CHANGE事件,也就是說用這種方法仍舊無法捕獲回車鍵的輸入。 三、攔截回車鍵的思路與方法 Windows操作系統(tǒng)下各個窗口、控件歸根結(jié)底都是通過系統(tǒng)的各種各樣的消息來相互協(xié)調(diào)、相互聯(lián)系的,而我們所遇到的這個問題換到消息的角度說就是如何使程序能響應(yīng)在
30、編輯框上輸入的回車鍵所發(fā)出的消息,只要能響應(yīng)到這個消息,剩下的工作都可以在消息處理函數(shù)中完成。所以有必要對Windows系統(tǒng)的消息機(jī)制做些了解。 每個Windows應(yīng)用程序開始執(zhí)行后,Windows都為該程序創(chuàng)建一個消息隊列(message queue),用來存放郵寄給該程序可能創(chuàng)建的各種不同窗口的消息。消息隊列中消息的結(jié)構(gòu)(MSG)為: typedef struct tagMSG /*msg*/ HWND hwnd;/窗口句柄,標(biāo)識接收消息的窗口。 UINT message;/消息標(biāo)識號,如WM_TIMER等。WPARAM wParam;/消息參數(shù),當(dāng)為鍵盤消息時,表示虛擬鍵碼如VK_RET
31、URN等。LPARAM lParam;/消息參數(shù)。 DWORD time;/郵寄消息的時間。 POINT pt;/郵寄消息時的光標(biāo)位置,用屏幕坐標(biāo)表示。 MSG; 在系統(tǒng)下最常用的消息循環(huán)是調(diào)用GetMessage()函數(shù)從消息隊列中取出消息,然后調(diào)用DespatchMessage() 函數(shù)讓系統(tǒng)把消息發(fā)送給窗口函數(shù),一般情況下其結(jié)果是把窗口的所有消息都傳送給窗口函數(shù)。但特殊情況下可以在GetMessage()函數(shù)獲得消息而又沒發(fā)送出去之前,通過TranslateMessage()函數(shù)可以中途對消息進(jìn)行解析,可以對指定的消息進(jìn)行攔截,攔截后即可以照樣發(fā)送出去,也可以不繼續(xù)發(fā)送,完成對該消息的攔
32、截,下面代碼是該過程的示例: MSG msg;while(GetMessage(&msg,NULL,NULL,NULL,NULL)TranslateMessage(&msg); /對攔截的消息進(jìn)行處理DispathchMessage(&msg); 由于按下回車鍵時把產(chǎn)生的消息加入到消息隊列中了,也傳給了編輯框,但僅僅是由于編輯框沒有能力處理該消息而造成了無法對回車鍵的響應(yīng),所以可以在消息循環(huán)里在把消息發(fā)送到編輯框之前就對消息進(jìn)行攔截,并對其進(jìn)行處理。其效果同編輯框響應(yīng)回車鍵是一樣的,僅在時序上有所提前而已。上述代碼是在SDK(Software Develope Kits)下使用的,在MFC(Microsoft Foundation Class)下早已對其進(jìn)行了封裝,可以通過重載虛函數(shù)PreTranslateMessage()對所關(guān)心的消息進(jìn)行解析: BOOL CTestView:PreTranslateMessage(MSG* pMsg) if (WM_KEYFIRST message & pMsg- message wParam=VK_RETURN ) UpdateData(TRUE);AfxMessage
溫馨提示
- 1. 本站所有資源如無特殊說明,都需要本地電腦安裝OFFICE2007和PDF閱讀器。圖紙軟件為CAD,CAXA,PROE,UG,SolidWorks等.壓縮文件請下載最新的WinRAR軟件解壓。
- 2. 本站的文檔不包含任何第三方提供的附件圖紙等,如果需要附件,請聯(lián)系上傳者。文件的所有權(quán)益歸上傳用戶所有。
- 3. 本站RAR壓縮包中若帶圖紙,網(wǎng)頁內(nèi)容里面會有圖紙預(yù)覽,若沒有圖紙預(yù)覽就沒有圖紙。
- 4. 未經(jīng)權(quán)益所有人同意不得將文件中的內(nèi)容挪作商業(yè)或盈利用途。
- 5. 人人文庫網(wǎng)僅提供信息存儲空間,僅對用戶上傳內(nèi)容的表現(xiàn)方式做保護(hù)處理,對用戶上傳分享的文檔內(nèi)容本身不做任何修改或編輯,并不能對任何下載內(nèi)容負(fù)責(zé)。
- 6. 下載文件中如有侵權(quán)或不適當(dāng)內(nèi)容,請與我們聯(lián)系,我們立即糾正。
- 7. 本站不保證下載資源的準(zhǔn)確性、安全性和完整性, 同時也不承擔(dān)用戶因使用這些下載資源對自己和他人造成任何形式的傷害或損失。
最新文檔
- 廠房租賃合同模板
- 2024工程顧問合同范本
- 地下車位租賃合同糾紛處理辦法
- 建筑工地施工升降機(jī)租賃合同
- 2024簡單的保姆用工合同協(xié)議書范本
- 制作合同范本(半成品)范本
- 跨國教育機(jī)構(gòu)合作辦學(xué)范本
- 2024公司收購合同范本
- 2024年貿(mào)易合同標(biāo)準(zhǔn)范本
- 委托管理合同范例大全
- 2024天貓男裝行業(yè)秋冬趨勢白皮書
- 《正確對待外來文化》名師課件
- 2024年綿陽科技城新區(qū)事業(yè)單位考核公開招聘高層次人才10人(高頻重點(diǎn)復(fù)習(xí)提升訓(xùn)練)共500題附帶答案詳解
- 中醫(yī)食療藥膳學(xué)智慧樹知到答案2024年四川護(hù)理職業(yè)學(xué)院
- 建筑項目安全風(fēng)險分級管控清單建筑風(fēng)險分級管控清單(范例)
- 馬背上的民族蒙古族少數(shù)民族蒙古族介紹課件
- 工程圖學(xué)(天津大學(xué))智慧樹知到期末考試答案章節(jié)答案2024年天津大學(xué)
- 農(nóng)村戶改廁施工協(xié)議書
- 當(dāng)代社會政策分析 課件 第十一章 殘疾人社會政策
- 家政公司未來發(fā)展計劃方案
- ISO28000:2022供應(yīng)鏈安全管理體系
評論
0/150
提交評論