对于子窗口控件,有时我们可能会想要获取子窗口的某些消息,比如在一个主窗口下有三个按钮,如果想要实现使用键盘Tab或者Shift-Tab键来使焦点切换于不同按钮之间,这时就可以使用子窗口类别化(Window Subclassing)的方法。
子窗口类别化:
按钮控件的窗口消息处理程序是Windows内部的。但是,将GWL_WNDPROC标识符作为参数来呼叫GetWindowLong,您就可以得到这个窗口消息处理程序的地址。另外,您可以呼叫SetWindowLong给指定按钮设定一个新的窗口消息处理程序,这个技术叫做「窗口子类别化」,非常有用。它能让您给现存的窗口消息处理程序设定「挂勾」,以便在自己的程序中处理一些消息,同时将其它所有消息传递给旧的窗口消息处理程序。
对三个按钮中的每一个,COLORS1使用SetWindowLong来设定新的滚动条窗口消息处理程序的地址,并取得现存滚动条窗口消息处理程序的地址:
for(i=0;i<3;i++) { hwndButton[i] =CreateWindow(TEXT("button"),ButtonName[i],WS_CHILD|BS_PUSHBUTTON, 0,0,0,0, hwnd, (HMENU)i, (HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),NULL); OldButtonWndProc[i] = (WNDPROC) SetWindowLong (hwndButton[i], GWL_WNDPROC, (LONG) NewWndProc)) ; }
现在,函数 NewWndProc 得到了Windows发送到 hwndButton 中 的滚动条窗口消息处理程序的全部消息。窗口消息处理程序在接收到Tab或者Shift-Tab键时,就将输入焦点改变到下一个(或者上一个)按钮窗口。它使用CallWindowProc呼叫旧的按钮窗口消息处理程序。
LRESULT CALLBACK NewWndProc (HWND hwnd, UINT message,WPARAM wParam, LPARAM lParam) { int id = GetWindowLong (hwnd, GWL_ID) ; switch (message) { case WM_KEYDOWN : if (wParam == VK_TAB) SetFocus (GetDlgItem (GetParent (hwnd), (id + (GetKeyState (VK_SHIFT) < 0 ? 2 : 1)) % 3)) ; break ; case WM_SETFOCUS : idFocus = id ; break ; } return CallWindowProc (OldButtonWndProc[id], hwnd, message, wParam,lParam) ; }