windows系统下面,每一个窗口都是一个WNDCLASS的实例。而一个WNDCLASS都有一个窗口过程(WndProc)与之对应。这不管是我们自己创建的WNDCLASS窗口还是windows标准窗口,比如button,edit等。Edit控件功能强大,能够处理字符输入删除编辑等,显然是windows系统实现的。对于Edit控件的窗口过程函数,我们是无法得到的(当然排除类似hook等方法)。由此,得到一个结论:
结论1:Edit,Button等windows标准窗口控件(The standard Microsoft Windows controls :edit controls, combo boxes, list boxes, buttons, scroll bars, and static controls) 和Windows通用控件,都有自己的窗口过程函数。
另外一个很现实的问题,键盘和鼠标这两种输入设备,同一个时间点,其输入的信息,只可能是针对一个窗口而言,只能与一个窗口句柄关联。这个应该很好理解,也就是说,在windows系统中,不管屏幕上显示了多少个窗口,最终得到的键盘和鼠标的输入数据,总是具有焦点的那个窗口(这个结论我没有验证,只是推测,所以不敢肯定,不敢肯定的是没有焦点的窗口是否也可以得到输入),暂且也作为一个结论吧:
结论2:windows系统中,同一个时间点上,只有一个窗口能够得到键盘和鼠标的输入数据。
一般说来,edit,button等所谓的控件,总是放在一个窗口之上的。所以当edit得到输入焦点的时候,键盘输入数据,就关联到edit控件的句柄上,从而被消息循环派遣到了edit的窗口过程函数里了。从而得到结论3:
结论3:与该窗口句柄相关的消息被派遣到该窗口的窗口过程函数里。
为了验证上面的结论,用一个代码示例之:
step1:用VC2005创建一个win32窗口程序,就用VC系统创建的代码,不选择“空的工程”
step2:定义一个全局变量:
HWND hEdit=NULL;
step3: 在窗口过程函数里,创建一个edit框,在窗口的WM_CREATE消息里处理:
LRESULT CALLBACK WndProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
..
case WM_CREATE:
hEdit = CreateWindow( _T("EDIT"), // predefined class
NULL, // no window title
WS_CHILD | WS_VISIBLE | WS_VSCROLL |
ES_LEFT | ES_MULTILINE | ES_AUTOVSCROLL,
0, 0, 400, 400, // set size in WM_SIZE message
hWnd, // parent window
(HMENU) ID_EDITCHILD, // edit control ID
hInst,
NULL); // pointer not needed
break;
...
到此,就手工创建了一个edit编辑框放在了一个窗口上了。
接下来验证edit框获取了鼠标键盘的输入,而其父窗口在edit获得输入时却无法获得消息。
step4:还是在窗口过程中,增加键盘按下和鼠标移动消息:
case WM_KEYDOWN:
{
short int key = (short int) wParam;
TCHAR szText[256]={0};
_stprintf( szText,_T("/n Key Down = %d") , key );
OutputDebugString( szText );
break;
}
case WM_MOUSEMOVE:
{
int x= LOWORD( lParam );
int y= HIWORD( lParam );
break;
}
编译运行后,可以发现,在edit框之外移动鼠标,按下键盘,窗口过程截获到该消息,但是如果在edit框内按键移动鼠标,均无法得到消息。
问题来了,我们如何处理edit编辑框的WM_KEYDOWN,WM_MOUSEMOVE消息呢?
如果熟悉MFC的同学,会很快回答这个问题,写一个类继承CEdit,步骤如下:
在头文件
class Editor : public CEdit
{
DECLARE_MESSAGE_MAP()
afx_msg void OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags);
}
在cpp文件
BEGIN_MESSAGE_MAP(Editor, CEdit)
//{{AFX_MSG_MAP(Editor)
ON_WM_KEYDOWN()
....
void Editor::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags)
{
...
然后就可以接收到消息了。
可是,MFC是如何做到的呢?