如果你希望監控使用者在 Edit Control 的輸入行為, 該怎麼做?
例如:
1. 隨時監控使用者在 Edit Control 的輸入 WM_KEYDOWN, 在顯示前先進行處理
ex: 使用者的輸入剛好是髒話的第一時間, 程式立即反應.
2. 或者是想建立高度互動性的程式, 偵測 [Enter] [上] [下] [ 左] [右] 的輸入
ex: 使用者輸入關鍵字的同時, 程式的某個相對應的文字會變成紅色等.
本文大綱
1. 在 MFC 下實做自己的 Edit Control
2. 直接用 Win32 解決這個問題
3. 下載完整範例程式
4. 不用 MFC 照樣可以吃掉 Edit Control 的 Message
在 MFC 下實做自己的 Edit Control
<sol>
這個問題在 MFC 很簡單, 只要寫一個自己的 Edit Control 類別, 繼承 CEdit 就可以了, 然後 override PreTranslateMessage method 即可.
作法如下:
----------------------- MFC 的作法 ------------------------------
class MyEditControl:public CEdit{
public:
// 關鍵片段:
BOOL PreTranslateMessage(MSG* pMsg){
BOOL bDone=FALSE;
switch(pMsg->message){
case WM_KEYDOWN :
bDone=KeyDownProcess(pMsg);
break;
default:
;
};
return bDone;
}// end of PreTranslateMessage
BOOL KeyDownProcess (MSG* pMsg){
switch(wParam){
case 13: // 輸入 Enter
break;
case 8: // Backspace
break;
case 37: // 左
break;
case 39: // 右
break;
case 38: // 上
break;
case 40: // 下
break;
}
}
} // end of MyEditControl class
-------------------------------------------------------------------
直接用 Win32 解決這個問題
可是呢? 如果不想用體積龐大的 MFC, 那 Win32 API 要怎麼做呢?
<sol>
只要用 SetWindowLongPtr 指令, 將 Edit Control 的 Window Procedure 轉成你的就可以了.
例如:
SetWindowLongPtr(hEdit1,GWLP_WNDPROC,
(LONG_PTR) 你的 Message 處理函式);
詳細作法如下:
-------------------------- Win32 的處理方式 -------------------------
A. 設定重新導向 edit control 的 window procedure
HWND hEdit1 = GetDlgItem(ghwndMainDlg, IDC_EDIT1);
// Step 1: 先取得原先的 Edit Control Window Procedure
oldEditControlProc=GetWindowLongPtr
(hEdit1,GWLP_WNDPROC);
if(oldEditControlProc==0){
MessageBox(NULL,
_T("取得原先的 Edit Control Window Procedure 處理失敗"),
_T("GetWindowLongPtr Error"),MB_OK);
return FALSE;
}
// Step 2: 重新導向 Edit Control Window Procedure 到
// 自己的特別處理
SetWindowLongPtr(hEdit1,GWLP_WNDPROC,
(LONG_PTR) EditControlProc);
B. Edit Control Message 特別處理函式
LRESULT CALLBACK EditControlProc(HWND hDlg,UINT message,UINT wParam,LONG lParam){
// 確定 oldEditControlProc 一定有位址
_ASSERTE(oldEditControlProc!=0);
switch (message)
{
case WM_KEYDOWN: // 收到 Edit1 WM_KEYDOWN message
switch(wParam){
case 13: // 輸入 Enter
break;
case 8: // Backspace
break;
case 37: // 左
break;
case 39: // 右
break;
case 38: // 上
break;
case 40: // 下
break;
}
return TRUE;
}
// 標明我們不處理這個 message, 交給別人處理
return CallWindowProc((WNDPROC)
oldEditControlProc,hDlg,message,wParam,lParam);
}
下載完整範例程式
Win32API 處理方法關鍵片段
Win32API 處理方法完整專案
附錄:
不用 MFC 照樣可以吃掉 Edit Control 的 Message
MFC 的 PreTranslateMessage 很厲害, 可以讓你決定是否要送出指定的 Message, 如果你在 Win32 裡面當然也可以直接在 message-loop 直接處理. 可是如果我們想直接在某個 Dialog 的 Edit Control 裡面, 吃掉某個使用者的按鍵訊息, 不傳出去, 那該怎麼做?
我很懶惰, 不想自己寫 CreateWindowEx 從頭開始建立 Edit Control, 所以我們可以使用 WM_GETDLGCODE 來解決我們的問題.
關鍵片段:
switch(message){
case WM_GETDLGCODE:
return DLGC_WANTCHARS; // 表示接下來的 WM_CHAR
// 會被吃掉, 不會送到後面處理.
}
很簡陋的例子:
int bEat=0; // 是否吃掉目前使用者的輸入
LRESULT CALLBACK EditControlProc(
HWND hDlg,UINT message,UINT wParam,LONG lParam){
switch (message) {
case WM_KEYDOWN:
switch(wParam){
case 13: // 輸入 Enter
if(符合狀態(){
bEat=1; // 符合狀態時, 執行吃掉的動作
}
break;
}
case WM_GETDLGCODE:
if(bEat==1){
bEat=0;
return DLGC_WANTCHARS; // 表示接下來的 WM_CHAR
// 會被吃掉, 不會送到後面處理.
}
} // end of switch
if(bEat==1){
return TRUE;
}else{
return CallWindowProc(
(WNDPROC)oldEditControlProc,hDlg,
message,wParam,lParam);
}
}
Enjoy.
by Jing.
沒有留言:
張貼留言