明輝手游網中心:是一個免費提供流行視頻軟件教程、在線學習分享的學習平臺!

特定的編輯框上完成對回車鍵的響應

[摘要]信息產業(yè)部電子第二十二研究所青島分所 郎銳 一、引言 在通常的以CEditView為基類的單文檔/多文檔視圖程序中,可以很好的響應鍵盤輸入的回車鍵,只需比較最近兩次的輸入的字符,看看最新輸入的字符是否內碼是13(0x0d,回車鍵的內碼)即可識別出來,而要單獨把一個編輯框放入對話框中卻根本不響應,這...
信息產業(yè)部電子第二十二研究所青島分所 郎銳

一、引言
在通常的以CEditView為基類的單文檔/多文檔視圖程序中,可以很好的響應鍵盤輸入的回車鍵,只需比較最近兩次的輸入的字符,看看最新輸入的字符是否內碼是13(0x0d,回車鍵的內碼)即可識別出來,而要單獨把一個編輯框放入對話框中卻根本不響應,這個看似簡單的問題在實際應用中還是解決起來比較困難的。尤其是當一個充當表單錄入的對話框上有若干個編輯框,這就要求在一個編輯框添完一項表單后用習慣的回車鍵將該編輯框上的數(shù)據讀取到內存中去,并自動將光標移動到下一個編輯框中準備填寫下一欄表單。無疑這種界面是十分人機友好的,使錄入人員不必去執(zhí)行每填一下表單就去按一下執(zhí)行讀入到緩存功能的按鈕的煩瑣操作。但上述功能的實現(xiàn)卻并不象其演示的功能那樣簡單,下面本文就對這項技術的實現(xiàn)及附帶的其他技術作簡要的介紹。
二、不能響應回車鍵的原因分析
之所以在以CEditView作為基類的程序中可以響應回車鍵,是由于該程序的視類本身就是一個Edit控件,這就是問題的關鍵所在。CEditView作為CView的派生類能響應從鍵盤輸入的各種消息,其中有和鍵盤輸入相關的WM_CHAR、WM_KEYDOWN、WM_KEYUP等消息。我們就可以在這些消息的響應函數(shù)中靈活地設計程序去捕捉到回車鍵的輸入,并執(zhí)行響應的操作。
當我們將編輯框作為一個普通的控件放到對話框上時情況就發(fā)生了變化。在此我們以CFormView為例,它也是CView的一個派生類,視是一個Form窗體(即對話框),當放有編輯框的窗體有回車鍵輸入時,由于只有編輯框可以接受從鍵盤輸入的字符,所以當鍵盤按下時統(tǒng)統(tǒng)把消息都發(fā)給了編輯框(在Windows下每個窗口、按鈕、編輯框都看作一個窗口,都可以接受消息),可以通過ClassWizard在"Object IDs"選中編輯框所對應的ID號,在右邊的消息框中可以看出該編輯框并不能響應WM_CHAR等消息,只能用EN_CHANGE事件來做類似的響應?僧斘覀兗尤肓藢υ撌录奶幚砗瘮(shù)時,卻又將回車鍵當作控制字符,當輸入回車鍵并不會激發(fā)EN_CHANGE事件,也就是說用這種方法仍舊無法捕獲回車鍵的輸入。
三、攔截回車鍵的思路與方法
Windows操作系統(tǒng)下各個窗口、控件歸根結底都是通過系統(tǒng)的各種各樣的消息來相互協(xié)調、相互聯(lián)系的,而我們所遇到的這個問題換到消息的角度說就是"如何使程序能響應在編輯框上輸入的回車鍵所發(fā)出的消息",只要能響應到這個消息,剩下的工作都可以在消息處理函數(shù)中完成。所以有必要對Windows系統(tǒng)的消息機制做些了解。
每個Windows應用程序開始執(zhí)行后,Windows都為該程序創(chuàng)建一個"消息隊列(message queue)",用來存放郵寄給該程序可能創(chuàng)建的各種不同窗口的消息。消息隊列中消息的結構(MSG)為:
typedef struct tagMSG{/*msg*/
HWND hwnd; //窗口句柄,標識接收消息的窗口。
UINT message; //消息標識號,如WM_TIMER等。
WPARAM wParam; //消息參數(shù),當為鍵盤消息時,表示虛擬鍵碼如VK_RETURN等。
LPARAM lParam;//消息參數(shù)。
DWORD time; //郵寄消息的時間。
POINT pt; //郵寄消息時的光標位置,用屏幕坐標表示。
}MSG;
在系統(tǒng)下最常用的消息循環(huán)是調用GetMessage()函數(shù)從消息隊列中取出消息,然后調用DespatchMessage() 函數(shù)讓系統(tǒng)把消息發(fā)送給窗口函數(shù),一般情況下其結果是把窗口的所有消息都傳送給窗口函數(shù)。但特殊情況下可以在GetMessage()函數(shù)獲得消息而又沒發(fā)送出去之前,通過TranslateMessage()函數(shù)可以中途對消息進行解析,可以對指定的消息進行攔截,攔截后即可以照樣發(fā)送出去,也可以不繼續(xù)發(fā)送,完成對該消息的攔截,下面代碼是該過程的示例:
MSG msg;
while(GetMessage(&msg,NULL,NULL,NULL,NULL){
TranslateMessage(&msg);
…… //對攔截的消息進行處理
DispathchMessage(&msg);
}
由于按下回車鍵時把產生的消息加入到消息隊列中了,也傳給了編輯框,但僅僅是由于編輯框沒有能力處理該消息而造成了無法對回車鍵的響應,所以可以在消息循環(huán)里在把消息發(fā)送到編輯框之前就對消息進行攔截,并對其進行處理。其效果同編輯框響應回車鍵是一樣的,僅在時序上有所提前而已。上述代碼是在SDK(Software Develope Kits)下使用的,在MFC(Microsoft Foundation Class)下早已對其進行了封裝,可以通過重載虛函數(shù)PreTranslateMessage()對所關心的消息進行解析:
BOOL CTestView::PreTranslateMessage(MSG* pMsg)
{
if (WM_KEYFIRST <= pMsg->message && pMsg->message <= WM_KEYLAST)
{
if(pMsg->wParam==VK_RETURN )
{
UpdateData(TRUE);
AfxMessageBox(m_Text);
}

}
return CFormView::PreTranslateMessage(pMsg);
}
在上面的代碼中,首先將pMsg->message所表示的消息同WM_KEYFIRST 和WM_KEYLAST比較,確定是鍵盤消息,然后通過消息參數(shù)pMsg->wParam的值來判斷是否是回車鍵(VK_RETURN,虛擬鍵碼可以從SDK相關資料查到)。如是,則可以將已輸入到編輯框中的字符讀取到m_Text中,并將其顯示出來。
四、對編輯框的識別
前面已經可以對回車鍵響應了,可一個表單窗體有若干個編輯框,其各自的處理方式不盡相同,這就有必要對編輯框進行識別、對不同的編輯框做不同的處理。而且當按下回車鍵時必須保證只有當前有焦點的編輯框能完成對回車鍵的響應動作,否則也就失去了實際意義。
在Windows下的程序中,所有的資源都是有唯一標號的,使每個資源對象能唯一的區(qū)別于其他資源,所以我們可以通過資源ID來對編輯框做出區(qū)別,使之完成各自的響應處理。在Microsoft Visual C++ 6.0下可以通過"View"菜單的"ID= Resource Symboles…"查到指定ID的資源標識號的實際數(shù)值,如在本例中的兩個編輯框IDC_EDIT1和IDC_EDIT2所對應的數(shù)值分別為1000和1001,對前面的解析消息的代碼做些改動,主要如下所示:
……
if(pMsg->wParam==VK_RETURN )
{
HWND hWnd=::GetFocus();
int iID=::GetDlgCtrlID(hWnd);
if(iID==1000)//第一個編輯框的標識為1000
{
UpdateData(TRUE);
AfxMessageBox(m_Text1);//顯示第一個編輯框的內容
}
if(iID==1001) //第二個編輯框的標識為1001
{
UpdateData(TRUE);
AfxMessageBox(m_Text2);//顯示第二個編輯框的內容
}
}
……
在此通過API函數(shù)::GetFocus()(注意前面的"::",標識是全局API函數(shù),而非某個類中的成員函數(shù))取得當前光標所處的(即有焦點的)編輯框的句柄,然后通過API函數(shù)::GetDlgCtrlID()根據這個句柄返回此窗口資源的ID 號,該ID號是動態(tài)獲取的,使之同預先查看好的編輯框的ID作下比較即可區(qū)分出是需要哪個編輯框對回車鍵作出響應。
小結:本文通過對消息的解析實現(xiàn)了對特定編輯框的回車鍵的響應,在對消息機制有了基本的了解之后,可以用與本文類似的方法,對代碼稍作改動,就可以使其他一些不能響應特殊消息的控件能接收、處理特定的消息。