完整程序在这里:

http://examples.oreilly.com/9781572319950/cd_contents/Chap07/Checker4/Checker4.c

ChildWndProc中的代码使我感到困惑:

 case WM_LBUTTONDOWN :
      SetWindowLong (hwnd, 0, 1 ^ GetWindowLong (hwnd, 0)) ;
      SetFocus (hwnd) ;
      InvalidateRect (hwnd, NULL, FALSE) ;
      return 0 ;

           // For focus messages, invalidate the window for repaint

 case WM_SETFOCUS:
      idFocus = GetWindowLong (hwnd, GWL_ID) ;

           // Fall through

 case WM_KILLFOCUS:
      InvalidateRect (hwnd, NULL, TRUE) ;
      return 0 ;


为什么在ChildWndProc中出现消息WM_LBUTTONDOWN

返回0之前的最后一条语句是InvalidateRect,因为在此之前,程序使用WM_SETFOCUS函数向其自身发送SetFocus消息,该消息属于WM_KILLFOCUS,后者也具有InvalidateRect,只有最后一个参数是TRUE,而不是FALSE

据我了解,该程序应在InvalidateRect中没有WM_LBUTTONDOWN的情况下正常运行,因为它会调用SetFocus,这将使该窗口无效,但是当我从InvalidateRect中注释掉WM_LBUTTONDOWN时,该程序不会单击鼠标或按钮后,请正确重新粉刷窗口。

为什么这样?为什么在WM_LBUTTONDOWN InvalidateRect中最后一个参数是FALSE,在WM_KILLFOCUS中它是TRUE

我正在Windows XP 32bit中运行MS Visual Studio C ++ 2010 Express。

最佳答案

调用SetFocus()不会无条件发送WM_SETFOCUS消息。如果在调用之前窗口已经具有焦点,则SetFocus()将不执行任何操作。

换句话说,仅在焦点更改时发送WM_SETFOCUS消息。

至于TRUE / FALSE参数,就是bErase,是在重新绘制之前先擦除整个窗口,还是在现有的窗口上绘制。在我的书中,这是一个性能黑客。如果您知道可以不删除窗口而逃脱(因为您只更新窗口的一小部分),则可以在此处传递TRUE

我认为这种优化在2015年没有太大价值。如果需要高性能的显示更新,则无论如何都要使用OpenGL或DirectX。

07-24 13:31