特定的編輯框上完成對回車鍵的響應(yīng)
發(fā)表時(shí)間:2024-06-18 來源:明輝站整理相關(guān)軟件相關(guān)文章人氣:
[摘要]信息產(chǎn)業(yè)部電子第二十二研究所青島分所 郎銳 一、引言 在通常的以CEditView為基類的單文檔/多文檔視圖程序中,可以很好的響應(yīng)鍵盤輸入的回車鍵,只需比較最近兩次的輸入的字符,看看最新輸入的字符是否內(nèi)碼是13(0x0d,回車鍵的內(nèi)碼)即可識別出來,而要單獨(dú)把一個(gè)編輯框放入對話框中卻根本不響應(yīng),這...
信息產(chǎn)業(yè)部電子第二十二研究所青島分所 郎銳
一、引言
在通常的以CEditView為基類的單文檔/多文檔視圖程序中,可以很好的響應(yīng)鍵盤輸入的回車鍵,只需比較最近兩次的輸入的字符,看看最新輸入的字符是否內(nèi)碼是13(0x0d,回車鍵的內(nèi)碼)即可識別出來,而要單獨(dú)把一個(gè)編輯框放入對話框中卻根本不響應(yīng),這個(gè)看似簡單的問題在實(shí)際應(yīng)用中還是解決起來比較困難的。尤其是當(dāng)一個(gè)充當(dāng)表單錄入的對話框上有若干個(gè)編輯框,這就要求在一個(gè)編輯框添完一項(xiàng)表單后用習(xí)慣的回車鍵將該編輯框上的數(shù)據(jù)讀取到內(nèi)存中去,并自動(dòng)將光標(biāo)移動(dòng)到下一個(gè)編輯框中準(zhǔn)備填寫下一欄表單。無疑這種界面是十分人機(jī)友好的,使錄入人員不必去執(zhí)行每填一下表單就去按一下執(zhí)行讀入到緩存功能的按鈕的煩瑣操作。但上述功能的實(shí)現(xiàn)卻并不象其演示的功能那樣簡單,下面本文就對這項(xiàng)技術(shù)的實(shí)現(xiàn)及附帶的其他技術(shù)作簡要的介紹。
二、不能響應(yīng)回車鍵的原因分析
之所以在以CEditView作為基類的程序中可以響應(yīng)回車鍵,是由于該程序的視類本身就是一個(gè)Edit控件,這就是問題的關(guān)鍵所在。CEditView作為CView的派生類能響應(yīng)從鍵盤輸入的各種消息,其中有和鍵盤輸入相關(guān)的WM_CHAR、WM_KEYDOWN、WM_KEYUP等消息。我們就可以在這些消息的響應(yīng)函數(shù)中靈活地設(shè)計(jì)程序去捕捉到回車鍵的輸入,并執(zhí)行響應(yīng)的操作。
當(dāng)我們將編輯框作為一個(gè)普通的控件放到對話框上時(shí)情況就發(fā)生了變化。在此我們以CFormView為例,它也是CView的一個(gè)派生類,視是一個(gè)Form窗體(即對話框),當(dāng)放有編輯框的窗體有回車鍵輸入時(shí),由于只有編輯框可以接受從鍵盤輸入的字符,所以當(dāng)鍵盤按下時(shí)統(tǒng)統(tǒng)把消息都發(fā)給了編輯框(在Windows下每個(gè)窗口、按鈕、編輯框都看作一個(gè)窗口,都可以接受消息),可以通過ClassWizard在"Object IDs"選中編輯框所對應(yīng)的ID號,在右邊的消息框中可以看出該編輯框并不能響應(yīng)WM_CHAR等消息,只能用EN_CHANGE事件來做類似的響應(yīng)。可當(dāng)我們加入了對該事件的處理函數(shù)時(shí),卻又將回車鍵當(dāng)作控制字符,當(dāng)輸入回車鍵并不會(huì)激發(fā)EN_CHANGE事件,也就是說用這種方法仍舊無法捕獲回車鍵的輸入。
三、攔截回車鍵的思路與方法
Windows操作系統(tǒng)下各個(gè)窗口、控件歸根結(jié)底都是通過系統(tǒng)的各種各樣的消息來相互協(xié)調(diào)、相互聯(lián)系的,而我們所遇到的這個(gè)問題換到消息的角度說就是"如何使程序能響應(yīng)在編輯框上輸入的回車鍵所發(fā)出的消息",只要能響應(yīng)到這個(gè)消息,剩下的工作都可以在消息處理函數(shù)中完成。所以有必要對Windows系統(tǒng)的消息機(jī)制做些了解。
每個(gè)Windows應(yīng)用程序開始執(zhí)行后,Windows都為該程序創(chuàng)建一個(gè)"消息隊(duì)列(message queue)",用來存放郵寄給該程序可能創(chuàng)建的各種不同窗口的消息。消息隊(duì)列中消息的結(jié)構(gòu)(MSG)為:
typedef struct tagMSG{/*msg*/
HWND hwnd; //窗口句柄,標(biāo)識接收消息的窗口。
UINT message; //消息標(biāo)識號,如WM_TIMER等。
WPARAM wParam; //消息參數(shù),當(dāng)為鍵盤消息時(shí),表示虛擬鍵碼如VK_RETURN等。
LPARAM lParam;//消息參數(shù)。
DWORD time; //郵寄消息的時(shí)間。
POINT pt; //郵寄消息時(shí)的光標(biāo)位置,用屏幕坐標(biāo)表示。
}MSG;
在系統(tǒng)下最常用的消息循環(huán)是調(diào)用GetMessage()函數(shù)從消息隊(duì)列中取出消息,然后調(diào)用DespatchMessage() 函數(shù)讓系統(tǒng)把消息發(fā)送給窗口函數(shù),一般情況下其結(jié)果是把窗口的所有消息都傳送給窗口函數(shù)。但特殊情況下可以在GetMessage()函數(shù)獲得消息而又沒發(fā)送出去之前,通過TranslateMessage()函數(shù)可以中途對消息進(jìn)行解析,可以對指定的消息進(jìn)行攔截,攔截后即可以照樣發(fā)送出去,也可以不繼續(xù)發(fā)送,完成對該消息的攔截,下面代碼是該過程的示例:
MSG msg;
while(GetMessage(&msg,NULL,NULL,NULL,NULL){
TranslateMessage(&msg);
…… //對攔截的消息進(jìn)行處理
DispathchMessage(&msg);
}
由于按下回車鍵時(shí)把產(chǎn)生的消息加入到消息隊(duì)列中了,也傳給了編輯框,但僅僅是由于編輯框沒有能力處理該消息而造成了無法對回車鍵的響應(yīng),所以可以在消息循環(huán)里在把消息發(fā)送到編輯框之前就對消息進(jìn)行攔截,并對其進(jìn)行處理。其效果同編輯框響應(yīng)回車鍵是一樣的,僅在時(shí)序上有所提前而已。上述代碼是在SDK(Software Develope Kits)下使用的,在MFC(Microsoft Foundation Class)下早已對其進(jìn)行了封裝,可以通過重載虛函數(shù)PreTranslateMessage()對所關(guān)心的消息進(jìn)行解析:
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相關(guān)資料查到)。如是,則可以將已輸入到編輯框中的字符讀取到m_Text中,并將其顯示出來。
四、對編輯框的識別
前面已經(jīng)可以對回車鍵響應(yīng)了,可一個(gè)表單窗體有若干個(gè)編輯框,其各自的處理方式不盡相同,這就有必要對編輯框進(jìn)行識別、對不同的編輯框做不同的處理。而且當(dāng)按下回車鍵時(shí)必須保證只有當(dāng)前有焦點(diǎn)的編輯框能完成對回車鍵的響應(yīng)動(dòng)作,否則也就失去了實(shí)際意義。
在Windows下的程序中,所有的資源都是有唯一標(biāo)號的,使每個(gè)資源對象能唯一的區(qū)別于其他資源,所以我們可以通過資源ID來對編輯框做出區(qū)別,使之完成各自的響應(yīng)處理。在Microsoft Visual C++ 6.0下可以通過"View"菜單的"ID= Resource Symboles…"查到指定ID的資源標(biāo)識號的實(shí)際數(shù)值,如在本例中的兩個(gè)編輯框IDC_EDIT1和IDC_EDIT2所對應(yīng)的數(shù)值分別為1000和1001,對前面的解析消息的代碼做些改動(dòng),主要如下所示:
……
if(pMsg->wParam==VK_RETURN )
{
HWND hWnd=::GetFocus();
int iID=::GetDlgCtrlID(hWnd);
if(iID==1000)//第一個(gè)編輯框的標(biāo)識為1000
{
UpdateData(TRUE);
AfxMessageBox(m_Text1);//顯示第一個(gè)編輯框的內(nèi)容
}
if(iID==1001) //第二個(gè)編輯框的標(biāo)識為1001
{
UpdateData(TRUE);
AfxMessageBox(m_Text2);//顯示第二個(gè)編輯框的內(nèi)容
}
}
……
在此通過API函數(shù)::GetFocus()(注意前面的"::",標(biāo)識是全局API函數(shù),而非某個(gè)類中的成員函數(shù))取得當(dāng)前光標(biāo)所處的(即有焦點(diǎn)的)編輯框的句柄,然后通過API函數(shù)::GetDlgCtrlID()根據(jù)這個(gè)句柄返回此窗口資源的ID 號,該ID號是動(dòng)態(tài)獲取的,使之同預(yù)先查看好的編輯框的ID作下比較即可區(qū)分出是需要哪個(gè)編輯框?qū)剀囨I作出響應(yīng)。
小結(jié):本文通過對消息的解析實(shí)現(xiàn)了對特定編輯框的回車鍵的響應(yīng),在對消息機(jī)制有了基本的了解之后,可以用與本文類似的方法,對代碼稍作改動(dòng),就可以使其他一些不能響應(yīng)特殊消息的控件能接收、處理特定的消息。