父子窗口焦点问题

以下权当学习笔记一篇,初学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.C(Mouse Hit-Test Demo Program No. 4)程序中一书中有以下说明:

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

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

 

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

……在风格相似的CHECKER2中,此程序可获得有输入焦点的子窗口的x和y坐标,并根据按下的特定方向键来改变它们。然后通过呼叫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引起,因(0,256)无效,接下来不存在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----------


下面是源代码:有点罗嗦
  /********************************************************************
      created:    2009/04/01
      created:    1:4:2009   15:27
      filename:     Z:/C++/t8/j.c
      file path:    Z:/C++/t8
      file base:    j
      file ext:    c
      author:        xcntime
  
      purpose:    windows程序设计
  *********************************************************************/
  #include <windows.h>
  #pragma warning(push,4)        //发现在Intel C/C++上没用???
  #pragma comment(linker, "/subsystem:windows /RELEASE ")
  #pragma  message(" 正在进行Windows平台下的GUI程序编译......")
  #pragma warning(once:177)
  
  #define MAXRECTS 3
  #define BLANK 10
  int iFocus = 0;    //子窗口号
  static int iflag = 0;
  
  HANDLE hFile;
  DWORD  dwBytesWritten;
  SYSTEMTIME st;
  static TCHAR szBuff[255];
  LRESULT CALLBACK ChildWndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  LRESULT CALLBACK WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam );
  TCHAR szChildClass[] = TEXT ( "ChildClass" );
  void fnWritefile(HANDLE hFile,TCHAR szBuff[],DWORD *lpdwBytesWritten)
  {
      SetFilePointer ( hFile, 0, NULL, FILE_END );    //没有容错代码
      WriteFile ( hFile, szBuff, lstrlen ( szBuff ), lpdwBytesWritten, NULL );
  }
  int WINAPI WinMain ( HINSTANCE hInstance, HINSTANCE hPrevInstance, LPSTR lpCmdLine, int nShowCmd )
  {
      WNDCLASS wndclass;
      HWND hWnd;
      MSG msg;
      static TCHAR szClassName[] = TEXT ( "程序类" );
  
      RtlZeroMemory ( &wndclass, sizeof ( wndclass ) );
      wndclass.style = CS_HREDRAW | CS_VREDRAW;
      wndclass.lpfnWndProc = WndProc;
      wndclass.lpszClassName = szClassName;
      wndclass.hInstance = hInstance;
      wndclass.hIcon = NULL;
      wndclass.hCursor = LoadCursor ( NULL, IDC_ARROW );
      wndclass.hbrBackground = CreateSolidBrush ( RGB ( 160, 190, 160 ) ); //(HBRUSH)GetStockObject(WHITE_BRUSH);
      wndclass.lpszMenuName = NULL;
      wndclass.cbClsExtra = 0;
      wndclass.cbWndExtra = 0;
  
      if ( !RegisterClass ( &wndclass ) )
      {
          MessageBox ( NULL, TEXT ( "本程序需要运行在WinNT系列操作系统上!" ), TEXT ( "Error" ), MB_OK | MB_ICONWARNING );
      }
  
      wndclass.lpfnWndProc = ChildWndProc;
      wndclass.lpszClassName = szChildClass;
      wndclass.hIcon = NULL;
      wndclass.cbWndExtra = sizeof ( long );
      RegisterClass ( &wndclass );
  
      hFile = CreateFile ( "d://MyLog.txt",         // create MYFILE.TXT
                           GENERIC_WRITE | GENERIC_READ,              // open for writing
                           FILE_SHARE_READ | FILE_SHARE_WRITE,                          // do not share
                           NULL,                         // no security
                           OPEN_ALWAYS,                // overwrite existing
                           FILE_ATTRIBUTE_NORMAL  ,     // normal file
  
                           NULL );                       // no attr. template
  
      if ( hFile == INVALID_HANDLE_VALUE )
      {
          MessageBox ( NULL, TEXT ( "文件创建失败!" ), TEXT ( "警告" ), MB_ICONWARNING );  // process error
          ExitProcess ( 0 );
      }
  
      hWnd = CreateWindow ( szClassName, TEXT ( "我的第N个程序" ), WS_OVERLAPPEDWINDOW,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            CW_USEDEFAULT,
                            NULL, NULL, hInstance, NULL );
      ShowWindow ( hWnd, nShowCmd );
      UpdateWindow ( hWnd );
  
      while ( GetMessage ( &msg, NULL, 0, 0 ) )
      {
          TranslateMessage ( &msg );
          DispatchMessage ( &msg );
      }
  
      return msg.wParam;
  }
  
  LRESULT CALLBACK WndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  {
      HDC hDc;                //设备描述
      PAINTSTRUCT ps;
      static RECT rect;    //已改动
  
      static int cxClient, cyClient, iCurLine = 0 ;    //当前窗口宽高
  
      TEXTMETRIC tm;
      static int cxChar, cyChar, iMaxWidth, cxCaps;    //字体宽高,属性
      TCHAR szBuffer[256];                //字体缓冲
  
      int i, j, k, x, y;                        //常用变量
  
      static int cxBlock, cyBlock;
      static int cxyStart, fColor;
      static HWND hChildWnd[MAXRECTS][MAXRECTS];
      static BOOL fRemain;
      POINT pt;
      switch ( msg )
      {
      case WM_CREATE:
          GetLocalTime ( &st );
          wsprintf ( szBuff, TEXT ( "---%4d-%2d%2d--%2d:%2d:%2d----------START----------/n序号|窗口对象|/t/t截获的消息|/t/t保存的活动窗口对象|/n" ),
                     st.wYear, st.wMonth, st.wDay,
                     st.wHour, st.wMinute, st.wMinute
                   );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          for ( x = 0;x < MAXRECTS;x++ )
          {
              for ( y = 0;y < MAXRECTS;y++ )
              {
                  wsprintf ( szBuffer, TEXT ( "%d:%d->" ), x, y );
                  hChildWnd[x][y] = CreateWindow ( szChildClass, NULL, WS_CHILDWINDOW | WS_VISIBLE,
                                                   0, 0, 0, 0, hWnd, ( HMENU ) ( y << 8 | x ),
                                                   ( HINSTANCE ) GetWindowLong ( hWnd, GWL_HINSTANCE ),
                                                   NULL );
              }
          }
          hDc = GetDC ( hWnd );
          GetTextMetrics ( hDc, &tm );    //字体设置
          cxChar = tm.tmAveCharWidth;
          cyChar = tm.tmHeight + tm.tmExternalLeading;
          cxCaps = ( tm.tmPitchAndFamily == 1 ? 1.5 : 1 ) * cxChar;
          iMaxWidth = cxCaps * 40 + 40 * cxChar;
          ReleaseDC ( hWnd, hDc );
          return 0;
  
      case WM_SIZE:
          cxClient = LOWORD ( lParam );
          cyClient = HIWORD ( lParam );
          cxBlock = cxClient / MAXRECTS - BLANK;
          cyBlock = cyClient / MAXRECTS - BLANK;
          cxyStart = ( cxClient - cxBlock * MAXRECTS + cyClient - cyBlock * MAXRECTS ) / 5;
  
          for ( x = 0;x < MAXRECTS;x++ )
          {
              for ( y = 0;y < MAXRECTS;y++ )
              {
                  MoveWindow ( hChildWnd[x][y], cxyStart + cxBlock *x, cxyStart + cyBlock *y,
                               cxBlock - BLANK, cyBlock - BLANK, TRUE );
              }
          }
          return 0;
  
          /*    case WM_KEYDOWN:
                  SetFocus(GetDlgItem(hWnd,iFocus=y<<8|x));
                  return 0;
          */
      case WM_SETFOCUS:
          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 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
  
          SetFocus ( GetDlgItem ( hWnd, iFocus ) );//注释这行
          return 0;
      case WM_KILLFOCUS:
          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 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
  
          InvalidateRect ( hWnd, NULL, TRUE );
          return 0;
      case WM_DESTROY:
          GetLocalTime ( &st );
          wsprintf ( szBuff, TEXT ( "---%4d-%2d%2d--%2d:%2d:%2d----------END----------/n/n/n" ), st.wYear, st.wMonth, st.wDay,
                     st.wHour, st.wMinute, st.wMinute );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          CloseHandle ( hFile );
          PostQuitMessage ( 0 );
          return 0;
      }
  
      return DefWindowProc ( hWnd, msg, wParam, lParam );
  }
  
  LRESULT CALLBACK ChildWndProc ( HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam )
  {
      HDC hDc;                //设备描述
      PAINTSTRUCT ps;
      static RECT rect;    //已改动
      static int iCurrentPos;
  
      iCurrentPos = GetWindowLong ( hWnd, GWL_ID );
      switch ( msg )
      {
      case WM_CREATE:
          SetWindowLong ( hWnd, 0, 0 );
          return 0;
      case WM_LBUTTONDOWN:
          SetWindowLong ( hWnd, 0,  1 ^ GetWindowLong ( hWnd, 0 ) );
          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_LBUTTONDOWN" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          SetFocus ( hWnd );//注释这行
          InvalidateRect ( hWnd, NULL, FALSE );
          return 0;
      case WM_PAINT:
          hDc = BeginPaint ( hWnd, &ps );
          GetClientRect ( hWnd, &rect );
          Rectangle ( hDc, BLANK, BLANK, rect.right - BLANK, rect.bottom - BLANK );
         TextOut ( hDc, rect.right / 3, rect.bottom / 2, szBuff,
                   wsprintf ( szBuff, TEXT ( "Child:(%d,%d)" ), ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1 )
                 );
          if ( GetWindowLong ( hWnd, 0 ) )
          {
              MoveToEx ( hDc, BLANK, BLANK, NULL );
             LineTo ( hDc, rect.right - BLANK, rect.bottom - BLANK );
             MoveToEx ( hDc, BLANK, rect.bottom - BLANK, NULL );
              LineTo ( hDc, rect.right - BLANK, BLANK );
          }
          EndPaint ( hWnd, &ps );
          return 0;
      case WM_KEYDOWN:
          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_KEYDOWN" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          return 0;
      case WM_SETFOCUS:
          iFocus = GetWindowLong ( hWnd, GWL_ID );
          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_SETFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          return 0;
      case WM_KILLFOCUS:
          wsprintf ( szBuff, TEXT ( "%3d/t:Child:(%d,%d)/t/t%-15s/t/tWindow:(%d.%d)/n" ), ++iflag,
                     ( iCurrentPos >> 8 ) + 1, ( iCurrentPos&0xFF ) + 1, TEXT ( "WM_KILLFOCUS" ),  ( iFocus >> 8 ) + 1, ( iFocus&0xFF ) + 1 );
          fnWritefile(hFile,szBuff,&dwBytesWritten);
          InvalidateRect ( hWnd, NULL, TRUE );
          return 0;
      }
      return DefWindowProc ( hWnd, msg, wParam, lParam );
  }


  • 3
    点赞
  • 10
    收藏
    觉得还不错? 一键收藏
  • 4
    评论
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值