[原创]关于"子窗口无法自动获得输入焦点"的验证

以下权当学习笔记一篇,初学Win32编程的一个小坎,:父子窗口的输入焦点问题,子窗口无法自动获得输入焦点?

程序窗口的输入焦点用于表示哪个窗口有资格接收键盘输入消息。带有输入焦点的窗口或是一个活动窗口,或者是该活动窗口的子窗口

当一个顶层窗口获得输入焦点时,Windows向该窗口发送WM_SETFOCUS消息,此窗口可将输入焦点重定位到它的子窗口上。子窗口不会自动获得输入焦点。失去输入焦点的窗口会收到WM_KILLFOCUS消息。当子窗口拥有输入焦点时,父窗口就不会处理键盘输入了。

用户使用按钮时.按钮获得输入焦点而其父窗口失去输入焦点.这时父窗口先收到WM_KILLFOCUS消息(wParam参数为获得输入焦点的窗口的句柄).然后获得输入焦点的窗口(按钮子窗口)收到一个WM_SETFOCUS消息(wParam参数为失去输入焦点的窗口的句柄).

所谓子窗口不会自动获得输入焦点的具体含义是:

1.         若一程序a父窗口A上有子窗口B,C,D,此时从另一程序b直接(不是先点击A,再点击B)用鼠标(例如:WM_LBUTTONDOWN)切换到a程序的B窗口上,a程序接受消息顺序是: 父窗口A响应收到的WM_SETFOCUS消息,继而子窗口B响应收到的WM_LBUTTONDOWN消息,一般这两个响应过程里都可以添加SetFocus( )函数以确定当前子窗口B具有输入焦点,一般添加SetFocus( B)使B获得焦点,当然Coder不添加SetFocus( B)B无法收到键盘消息.

2.         但是!?.若从程序a子窗口B直接切换到子窗口C,a程序接受消息顺序是:子窗口B响应收到的WM_LBUTTONDOWN,继而B窗口响应WM_KILLFOCUS,C响应WM_SETFOCUS.这个情况大家们似乎不屑于说,或者不值得提.

Charles Petzold所著Programming Windows一书中第七章的7-5 CHECKER4.CMouse Hit-Test Demo Program No. 4)程序中一书中有以下说明:

CHECKER4中,整体变量idFocus用于保存目前输入焦点窗口的子窗口ID。我在前面说过,当您在子窗口上面单击鼠标时,它们不会自动获得输入焦点。因此,CHECKER4中的父窗口将通过呼叫下面的函数来处理WM_SETFOCUS消息:

SetFocus (GetDlgItem (hwnd, idFocus)) ;这样设定一个子窗口为输入焦点。

 

ChildWndProc处理WM_SETFOCUSWM_KILLFOCUS消息。对于WM_SETFOCUS,它将保存在整体变量idFocus中接收输入焦点的子窗口ID……

……在风格相似的CHECKER2中,此程序可获得有输入焦点的子窗口的xy坐标,并根据按下的特定方向键来改变它们。然后通过呼叫SetFocus将输入焦点设定给新的子窗口。

 

上述基本肯定了我的看法.

 

下面是一个验证程序,通过注释掉回调函数的SetFocus()观察其用法,仅当学习了哈,验证途径:打开画图程序(随便一个其他Windows程序),运行编译后的程序j.exe,左键单击子窗口(1,1),(1,2),键盘输入字母a,切换到画图程序,再切换到j.exe的标题栏,键盘输入字母b,关闭j.exe,查看d://MyLog.txt内容,顺序不要错了哈,

---2009- 4 5--21:50:50----------START----------                  //保留父子函数体中的SetFocus();

序号|窗口对象|             截获的消息|          保存的活动窗口对象|

  1  :Parent:          WM_SETFOCUS                     Window:(0.256)//总是父窗口先收到哈

  2  :Parent:          WM_KILLFOCUS                    Window:(0.256)// 父窗口函数SetFocus引起,因(0256)无效,接下来不存在Window:(0.256) WM_SETFOCUS,iFocus初始值改为0就是另外结果.

  3  :Child:(2,1)           WM_LBUTTONDOWN              Window:(0.256)// 单击子窗口(1,1),

  4  :Child:(2,1)           WM_SETFOCUS              Window:(2.1) // 子窗口函数中的SetFocus引起

  5  :Child:(2,2)           WM_LBUTTONDOWN              Window:(2.1)// 单击子窗口(1,2)

  6  :Child:(2,1)           WM_KILLFOCUS             Window:(2.1)

  7  :Child:(2,2)           WM_SETFOCUS              Window:(2.2) // 子窗口函数中的SetFocus引起

  8  :Child:(2,2)           WM_KEYDOWN                   Window:(2.2)// 输入字母a

  9  :Child:(2,2)           WM_KILLFOCUS             Window:(2.2)

10  :Parent:          WM_SETFOCUS                     Window:(2.2)

 11  :Parent:          WM_KILLFOCUS                    Window:(2.2) // 父窗口函数中的SetFocus引起

 12  :Child:(2,2)           WM_SETFOCUS              Window:(2.2) // 父窗口函数中的SetFocus引起

 13  :Child:(2,2)           WM_KEYDOWN                   Window:(2.2)// 在保存的活动窗口输入字母b,

 14  :Child:(2,2)           WM_KILLFOCUS             Window:(2.2)//失去焦点,退出程序

---2009- 4 5--21:50:50----------END----------

 

 

---2009- 4 5--21:53:53----------START----------                 //仅留子函数体中的SetFocus();

序号|窗口对象|             截获的消息|          保存的活动窗口对象|

  1  :Parent:          WM_SETFOCUS                     Window:(0.256)

  2  :Child:(2,1)           WM_LBUTTONDOWN              Window:(0.256) // 单击子窗口(1,1)

  3  :Parent:          WM_KILLFOCUS                    Window:(0.256)

  4  :Child:(2,1)           WM_SETFOCUS              Window:(2.1)

  5  :Child:(2,2)           WM_LBUTTONDOWN              Window:(2.1) // 单击子窗口(1,2)

  6  :Child:(2,1)           WM_KILLFOCUS             Window:(2.1)

  7  :Child:(2,2)           WM_SETFOCUS              Window:(2.2)

  8  :Child:(2,2)           WM_KEYDOWN                   Window:(2.2) //输入字母a

  9  :Child:(2,2)           WM_KEYDOWN                   Window:(2.2)// 输入字母b

 10  :Child:(2,2)           WM_KILLFOCUS             Window:(2.2)

 11  :Parent:          WM_SETFOCUS                     Window:(2.2)

 12  :Parent:          WM_KILLFOCUS                    Window:(2.2)

---2009- 4 5--21:53:53----------END----------

 

 

---2009- 4 5--21:54:54----------START----------                  //仅留父函数体中的SetFocus();

序号|窗口对象|             截获的消息|          保存的活动窗口对象|

  1  :Parent:          WM_SETFOCUS                     Window:(0.256)

  2  :Parent:          WM_KILLFOCUS                    Window:(0.256) // 父窗口函数中的SetFocus引起

  3  :Child:(2,1)           WM_LBUTTONDOWN              Window:(0.256) // 单击子窗口(1,1)

  4  :Child:(2,2)           WM_LBUTTONDOWN              Window:(0.256) // 单击子窗口(1,2)

  5  :Parent:          WM_SETFOCUS                     Window:(0.256)//子窗口无法响应键盘输入

  6  :Parent:          WM_KILLFOCUS                    Window:(0.256)

---2009- 4 5--21:54:54----------END----------

 

下面是源代码:有点罗嗦

001  /********************************************************************
002      created:    2009/04/01
003      created:    1:4:2009   15:27
004      filename:     Z:/C++/t8/j.c
005      file path:    Z:/C++/t8
006      file base:    j
007      file ext:    c
008      author:        xcntime
009  
010      purpose:    windows程序设计
011  *********************************************************************/
012  #include <windows.h>
013  #pragma warning(push,4)        //发现在Intel C/C++上没用???
014  #pragma comment(linker, "/subsystem:windows /RELEASE ")
015  #pragma  message(" 正在进行Windows平台下的GUI程序编译......")
016  #pragma warning(once:177)
017  
018  #define MAXRECTS 3
019  #define BLANK 10
020  int iFocus = 0;    //子窗口号
021  static int iflag = 0;
022  
023  HANDLE hFile;
024  DWORD  dwBytesWritten;
025  SYSTEMTIME st;
026  static TCHAR szBuff[255];
027  LRESULT CALLBACK ChildWndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
028  LRESULT CALLBACK WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
029  TCHAR szChildClass[] = TEXT ( "ChildClass" );
030  void fnWritefile(HANDLE hFile,TCHAR szBuff[],DWORD *lpdwBytesWritten)
031  {
032      SetFilePointer ( hFile, 0, NULL, FILE_END );    //没有容错代码
033      WriteFile ( hFile, szBuff, lstrlen ( szBuff ), lpdwBytesWritten, NULL );
034  }
035  int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
036  {
037      WNDCLASS wndclass;
038      HWND hWnd;
039      MSG msg;
040      static TCHAR szClassName[] = TEXT ( "程序类" );
041  
042      RtlZeroMemory ( &wndclass, sizeof ( wndclass ) );
043      wndclass.style = CS_HREDRAW | CS_VREDRAW;
044      wndclass.lpfnWndProc = WndProc;
045      wndclass.lpszClassName = szClassName;
046      wndclass.hInstance = hInstance;
047      wndclass.hIcon = NULL;
048      wndclass.hCursor = LoadCursor ( NULL, IDC_ARROW );
049      wndclass.hbrBackground = CreateSolidBrush ( RGB ( 160, 190, 160 ) ); //(HBRUSH)GetStockObject(WHITE_BRUSH);
050      wndclass.lpszMenuName = NULL;
051      wndclass.cbClsExtra = 0;
052      wndclass.cbWndExtra = 0;
053  
054      if ( !RegisterClass ( &wndclass ) )
055      {
056          MessageBox ( NULL, TEXT ( "本程序需要运行在WinNT系列操作系统上!" ), TEXT ( "Error" ), MB_OK | MB_ICONWARNING );
057      }
058  
059      wndclass.lpfnWndProc = ChildWndProc;
060      wndclass.lpszClassName = szChildClass;
061      wndclass.hIcon = NULL;
062      wndclass.cbWndExtra = sizeof ( long );
063      RegisterClass ( &wndclass );
064  
065      hFile = CreateFile ( "d://MyLog.txt",         // create MYFILE.TXT
066                           GENERIC_WRITE | GENERIC_READ,              // open for writing
067                           FILE_SHARE_READ | FILE_SHARE_WRITE,                          // do not share
068                           NULL,                         // no security
069                           OPEN_ALWAYS,                // overwrite existing
070                           FILE_ATTRIBUTE_NORMAL  ,     // normal file
071  
072                           NULL );                       // no attr. template
073  
074      if ( hFile == INVALID_HANDLE_VALUE )
075      {
076          MessageBox ( NULL, TEXT ( "文件创建失败!" ), TEXT ( "警告" ), MB_ICONWARNING );  // process error
077          ExitProcess ( 0 );
078      }
079  
080      hWnd = CreateWindow ( szClassName, TEXT ( "我的第N个程序" ), WS_OVERLAPPEDWINDOW,
081                            CW_USEDEFAULT,
082                            CW_USEDEFAULT,
083                            CW_USEDEFAULT,
084                            CW_USEDEFAULT,
085                            NULL, NULL, hInstance, NULL );
086      ShowWindow ( hWnd, nShowCmd );
087      UpdateWindow ( hWnd );
088  
089      while ( GetMessage ( &msg, NULL, 0, 0 ) )
090      {
091          TranslateMessage ( &msg );
092          DispatchMessage ( &msg );
093      }
094  
095      return msg.wParam;
096  }
097  
098  LRESULT CALLBACK WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
099  {
100      HDC hDc;                //设备描述
101      PAINTSTRUCT ps;
102      static RECT rect;    //已改动
103  
104      static int cxClient, cyClient, iCurLine = 0 ;    //当前窗口宽高
105  
106      TEXTMETRIC tm;
107      static int cxChar, cyChar, iMaxWidth, cxCaps;    //字体宽高,属性
108      TCHAR szBuffer[256];                //字体缓冲
109  
110      int i, j, k, x, y;                        //常用变量
111  
112      static int cxBlock, cyBlock;
113      static int cxyStart, fColor;
114      static HWND hChildWnd[MAXRECTS][MAXRECTS];
115      static BOOL fRemain;
116      POINT pt;
117      switch ( msg )
118      {
119      case WM_CREATE:
120          GetLocalTime ( &st );
121          wsprintf ( szBuff, TEXT ( "---%4d-%2d%2d--%2d:%2d:%2d----------START----------/n序号|窗口对象|/t/t截获的消息|/t/t保存的活动窗口对象|/n" ),
122                     st.wYear, st.wMonth, st.wDay,
123                     st.wHour, st.wMinute, st.wMinute
124                   );
125          fnWritefile(hFile,szBuff,&dwBytesWritten);
126          for ( x = 0;x < MAXRECTS;x++ )
127          {
128              for ( y = 0;y < MAXRECTS;y++ )
129              {
130                  wsprintf ( szBuffer, TEXT ( "%d:%d->" ), x, y );
131                  hChildWnd[x][y] = CreateWindow ( szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,
132                                                   0, 0, 0, 0, hWnd, ( HMENU ) ( y << 8 | x ),
133                                                   ( HINSTANCE ) GetWindowLong ( hWnd, GWL_HINSTANCE ),
134                                                   NULL );
135              }
136          }
137          hDc = GetDC ( hWnd );
138          GetTextMetrics ( hDc, &tm );    //字体设置
139          cxChar = tm.tmAveCharWidth;
140          cyChar = tm.tmHeight + tm.tmExternalLeading;
141          cxCaps = ( tm.tmPitchAndFamily == 1 ? 1.5 : 1 ) * cxChar;
142          iMaxWidth = cxCaps * 40 + 40 * cxChar;
143          ReleaseDC ( hWnd, hDc );
144          return 0;
145  
146      case WM_SIZE:
147          cxClient = LOWORD ( lParam );
148          cyClient = HIWORD ( lParam );
149          cxBlock = cxClient / MAXRECTS - BLANK;
150          cyBlock = cyClient / MAXRECTS - BLANK;
151          cxyStart = ( cxClient - cxBlock * MAXRECTS + cyClient - cyBlock * MAXRECTS ) / 5;
152  
153          for ( x = 0;x < MAXRECTS;x++ )
154          {
155              for ( y = 0;y < MAXRECTS;y++ )
156              {
157                  MoveWindow ( hChildWnd[x][y], cxyStart + cxBlock *x, cxyStart + cyBlock *y,
158                               cxBlock - BLANK, cyBlock - BLANK, TRUE );
159              }
160          }
161          return 0;
162  
163          /*    case WM_KEYDOWN:
164                  SetFocus(GetDlgItem(hWnd,iFocus=y<<8|x));
165                  return 0;
166          */
167      case WM_SETFOCUS:
168          wsprintf ( szBuff, TEXT ( "%3d/t:Parent:/t/t%-15s/t/t/tWindow:(%d.%d)/n" ), ++iflag, TEXT ( "WM_SETFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
169          fnWritefile(hFile,szBuff,&dwBytesWritten);
170  
171          SetFocus ( GetDlgItem ( hWnd, iFocus ) );//注释这行
172          return 0;
173      case WM_KILLFOCUS:
174          wsprintf ( szBuff, TEXT ( "%3d/t:Parent:/t/t%-15s/t/t/tWindow:(%d.%d)/n" ), ++iflag, TEXT ( "WM_KILLFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
175          fnWritefile(hFile,szBuff,&dwBytesWritten);
176  
177          InvalidateRect ( hWnd, NULL, TRUE );
178          return 0;
179      case WM_DESTROY:
180          GetLocalTime ( &st );
181          wsprintf ( szBuff, TEXT ( "---%4d-%2d%2d--%2d:%2d:%2d----------END----------/n/n/n" ), st.wYear, st.wMonth, st.wDay,
182                     st.wHour, st.wMinute, st.wMinute );
183          fnWritefile(hFile,szBuff,&dwBytesWritten);
184          CloseHandle ( hFile );
185          PostQuitMessage ( 0 );
186          return 0;
187      }
188  
189      return DefWindowProc ( hWnd, msg, wParam, lParam );
190  }
191  
192  LRESULT CALLBACK ChildWndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
193  {
194      HDC hDc;                //设备描述
195      PAINTSTRUCT ps;
196      static RECT rect;    //已改动
197      static int iCurrentPos;
198  
199      iCurrentPos = GetWindowLong ( hWnd, GWL_ID );
200      switch ( msg )
201      {
202      case WM_CREATE:
203          SetWindowLong ( hWnd, 0, 0 );
204          return 0;
205      case WM_LBUTTONDOWN:
206          SetWindowLong ( hWnd, 0,  1 ^ GetWindowLong ( hWnd, 0 ) );
207          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
208                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_LBUTTONDOWN" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
209          fnWritefile(hFile,szBuff,&dwBytesWritten);
210          SetFocus ( hWnd );//注释这行
211          InvalidateRect ( hWnd, NULL, FALSE );
212          return 0;
213      case WM_PAINT:
214          hDc = BeginPaint ( hWnd, &ps );
215          GetClientRect ( hWnd, &rect );
216          Rectangle ( hDc, BLANK, BLANK, rect.right - BLANK, rect.bottom - BLANK );
217          TextOut ( hDc, rect.right / 3, rect.bottom / 2, szBuff,
218                    wsprintf ( szBuff, TEXT ( "Child:(%d,%d)" ), ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1 )
219                  );
220          if ( GetWindowLong ( hWnd, 0 ) )
221          {
222              MoveToEx ( hDc, BLANK, BLANK, NULL );
223              LineTo ( hDc, rect.right - BLANK, rect.bottom - BLANK );
224              MoveToEx ( hDc, BLANK, rect.bottom - BLANK, NULL );
225              LineTo ( hDc, rect.right - BLANK, BLANK );
226          }
227          EndPaint ( hWnd, &ps );
228          return 0;
229      case WM_KEYDOWN:
230          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
231                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_KEYDOWN" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
232          fnWritefile(hFile,szBuff,&dwBytesWritten);
233          return 0;
234      case WM_SETFOCUS:
235          iFocus = GetWindowLong ( hWnd, GWL_ID );
236          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
237                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_SETFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
238          fnWritefile(hFile,szBuff,&dwBytesWritten);
239          return 0;
240      case WM_KILLFOCUS:
241          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
242                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_KILLFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
243          fnWritefile(hFile,szBuff,&dwBytesWritten);
244          InvalidateRect ( hWnd, NULL, TRUE );
245          return 0;
246      }
247      return DefWindowProc ( hWnd, msg, wParam, lParam );
248  }
249  
250  

  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 5
    评论
评论 5
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值