关于窗口焦点

windows程序设计 第七章 鼠标 CHECKER.C程序

先上代码:

  1 /*-------------------------------------------------
  2    CHECKER4.C -- Mouse Hit-Test Demo Program No. 4
  3                  (c) Charles Petzold, 1998
  4   -------------------------------------------------*/
  5 
  6 #include <windows.h>
  7 
  8 #define DIVISIONS 5
  9 
 10 LRESULT CALLBACK WndProc   (HWND, UINT, WPARAM, LPARAM) ;
 11 LRESULT CALLBACK ChildWndProc (HWND, UINT, WPARAM, LPARAM) ;
 12 
 13 int   idFocus = 0 ;
 14 TCHAR szChildClass[] = TEXT ("Checker4_Child") ;
 15 
 16 int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
 17                     PSTR szCmdLine, int iCmdShow)
 18 {
 19      static TCHAR szAppName[] = TEXT ("Checker4") ;
 20      HWND         hwnd ;
 21      MSG          msg ;
 22      WNDCLASS     wndclass ;
 23      
 24      wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
 25      wndclass.lpfnWndProc   = WndProc ;
 26      wndclass.cbClsExtra    = 0 ;
 27      wndclass.cbWndExtra    = 0 ;
 28      wndclass.hInstance     = hInstance ;
 29      wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
 30      wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
 31      wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
 32      wndclass.lpszMenuName  = NULL ;
 33      wndclass.lpszClassName = szAppName ;
 34      
 35      if (!RegisterClass (&wndclass))
 36      {
 37           MessageBox (NULL, TEXT ("Program requires Windows NT!"), 
 38                       szAppName, MB_ICONERROR) ;
 39           return 0 ;
 40      }
 41      
 42      wndclass.lpfnWndProc   = ChildWndProc ;
 43      wndclass.cbWndExtra    = sizeof (long) ;
 44      wndclass.hIcon         = NULL ;
 45      wndclass.lpszClassName = szChildClass ;
 46      
 47      RegisterClass (&wndclass) ;
 48      
 49      hwnd = CreateWindow (szAppName, TEXT ("Checker4 Mouse Hit-Test Demo"),
 50                           WS_OVERLAPPEDWINDOW,
 51                           CW_USEDEFAULT, CW_USEDEFAULT,
 52                           CW_USEDEFAULT, CW_USEDEFAULT,
 53                           NULL, NULL, hInstance, NULL) ;
 54      
 55      ShowWindow (hwnd, iCmdShow) ;
 56      UpdateWindow (hwnd) ;
 57      
 58      while (GetMessage (&msg, NULL, 0, 0))
 59      {
 60           TranslateMessage (&msg) ;
 61           DispatchMessage (&msg) ;
 62      }
 63      return msg.wParam ;
 64 }
 65 
 66 LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
 67 {
 68      static HWND hwndChild[DIVISIONS][DIVISIONS] ;
 69      int         cxBlock, cyBlock, x, y ;
 70      
 71      switch (message)
 72      {
 73      case WM_CREATE :
 74           for (x = 0 ; x < DIVISIONS ; x++)
 75                for (y = 0 ; y < DIVISIONS ; y++)
 76                     hwndChild[x][y] = CreateWindow (szChildClass, NULL,
 77                               WS_CHILDWINDOW | WS_VISIBLE,
 78                               0, 0, 0, 0,
 79                               hwnd, (HMENU) (y << 8 | x),
 80                               (HINSTANCE) GetWindowLong (hwnd, GWL_HINSTANCE),
 81                               NULL) ;
 82           return 0 ;
 83                
 84      case WM_SIZE :
 85           cxBlock = LOWORD (lParam) / DIVISIONS ;
 86           cyBlock = HIWORD (lParam) / DIVISIONS ;
 87           
 88           for (x = 0 ; x < DIVISIONS ; x++)
 89                 for (y = 0 ; y < DIVISIONS ; y++)
 90                     MoveWindow (hwndChild[x][y],
 91                                 x * cxBlock, y * cyBlock,
 92                                 cxBlock, cyBlock, TRUE) ;
 93           return 0 ;
 94                        
 95      case WM_LBUTTONDOWN :
 96           MessageBeep (0) ;
 97           return 0 ;
 98 
 99           // On set-focus message, set focus to child window
100 
101      case WM_SETFOCUS:
102           SetFocus (GetDlgItem (hwnd, idFocus)) ;
103           return 0 ;
104 
105           // On key-down message, possibly change the focus window
106 
107      case WM_KEYDOWN:
108           x = idFocus & 0xFF ;
109           y = idFocus >> 8 ;
110 
111           switch (wParam)
112           {
113           case VK_UP:    y-- ;                    break ;
114           case VK_DOWN:  y++ ;                    break ;
115           case VK_LEFT:  x-- ;                    break ;
116           case VK_RIGHT: x++ ;                    break ;
117           case VK_HOME:  x = y = 0 ;              break ;
118           case VK_END:   x = y = DIVISIONS - 1 ;  break ;
119           default:       return 0 ;
120           }
121 
122           x = (x + DIVISIONS) % DIVISIONS ;
123           y = (y + DIVISIONS) % DIVISIONS ;
124 
125           idFocus = y << 8 | x ;
126 
127           SetFocus (GetDlgItem (hwnd, idFocus)) ;
128           return 0 ;
129 
130      case WM_DESTROY :
131           PostQuitMessage (0) ;
132           return 0 ;
133      }
134      return DefWindowProc (hwnd, message, wParam, lParam) ;
135 }
136 
137 LRESULT CALLBACK ChildWndProc (HWND hwnd, UINT message, 
138                                WPARAM wParam, LPARAM lParam)
139 {
140      HDC         hdc ;
141      PAINTSTRUCT ps ;
142      RECT        rect ;
143      
144      switch (message)
145      {
146      case WM_CREATE :
147           SetWindowLong (hwnd, 0, 0) ;       // on/off flag
148           return 0 ;
149 
150      case WM_KEYDOWN:
151                // Send most key presses to the parent window
152           
153           if (wParam != VK_RETURN && wParam != VK_SPACE)
154           {
155                SendMessage (GetParent (hwnd), message, wParam, lParam) ;
156                return 0 ;
157           }
158                // For Return and Space, fall through to toggle the square
159           
160      case WM_LBUTTONDOWN :
161           SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
162           SetFocus (hwnd) ;
163           InvalidateRect (hwnd, NULL, FALSE) ;
164           return 0 ;
165 
166                // For focus messages, invalidate the window for repaint
167           
168      case WM_SETFOCUS:
169           idFocus = GetWindowLong (hwnd, GWL_ID) ;
170 
171                // Fall through
172 
173      case WM_KILLFOCUS:
174           InvalidateRect (hwnd, NULL, TRUE) ;
175           return 0 ;
176           
177      case WM_PAINT :
178           hdc = BeginPaint (hwnd, &ps) ;
179           
180           GetClientRect (hwnd, &rect) ;
181           Rectangle (hdc, 0, 0, rect.right, rect.bottom) ;
182 
183                // Draw the "x" mark
184           
185           if (GetWindowLong (hwnd, 0))
186           {
187                MoveToEx (hdc, 0,          0, NULL) ;
188                LineTo   (hdc, rect.right, rect.bottom) ;
189                MoveToEx (hdc, 0,          rect.bottom, NULL) ;
190                LineTo   (hdc, rect.right, 0) ;
191           }
192 
193                // Draw the "focus" rectangle
194           
195           if (hwnd == GetFocus ())
196           {
197                rect.left   += rect.right / 10 ;
198                rect.right  -= rect.left ;
199                rect.top    += rect.bottom / 10 ;
200                rect.bottom -= rect.top ;
201 
202                SelectObject (hdc, GetStockObject (NULL_BRUSH)) ;
203                SelectObject (hdc, CreatePen (PS_DASH, 0, 0)) ;
204                Rectangle (hdc, rect.left, rect.top, rect.right, rect.bottom) ;
205                DeleteObject (SelectObject (hdc, GetStockObject (BLACK_PEN))) ;
206           }
207 
208           EndPaint (hwnd, &ps) ;
209           return 0 ;
210      }
211      return DefWindowProc (hwnd, message, wParam, lParam) ;
212 }

刚开始看程序不仔细,子窗口的回调函数里面关于键盘消息的处理没有仔细看,于是很是纠结:

我记得只有拥有焦点的窗口才能收到键盘消息的啊,可是这里只看到主窗口把焦点设置在子窗口上,没看见子窗口把焦点还回去啊。。。

那么为什么按键盘上的那些移动键,就好像消息被发送到了主窗口的调用函数一样呢?纠结了好久

后来才看到第155行的SendMessage(),顿时有想抽死自己的冲动。

 

但是,虽然浪费了很多时间,这种豁然开朗的感觉真是太爽了~

 

另外,本书里的程序真的值得一看,好多有意思的写法(可能是我孤陋寡闻了)

比如,122、123行,如果我来写,肯定是复杂的逻辑,判断是否小于0,如果小于0则加上DIVISIONS,如果大于DIVISIONS则减去DIVISIONS等等。。。

看到这种写法,真的有一种惊艳的感觉~

程序的世界真是太美妙了o(∩_∩)o 

原文地址:https://www.cnblogs.com/02xiaoma/p/2550829.html