博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
《Windows程序设计》第4章
阅读量:4204 次
发布时间:2019-05-26

本文共 2832 字,大约阅读时间需要 9 分钟。

  在处理WM_PAINT消息期间,窗口过程在调用了BeginPaint()之后,整个客户区即变得有效。程序也可以调用ValidateRect()使客户区内的任意矩形区域变为有效。如是调用该函数使得整个客户区全部变为有效,则当前消息队列中的所有WM_PAINT消息都会被删除。

  在处理WM_PAINT消息时必须成对调用BeginPaint()和EndPaint()。如果窗口过程不处理WM_PAINT消息,则必须将WM_PAINT消息传递给DefWindowProc()。该项函数依次调用BeginPaint()和EndPaint()。它仅仅使无效区域变得有效。

  case WM_PAINT:

    BeginPaint(hwnd, &ps);

    EndPaint(hwnd, &ps);

    return 0;

  但是以下的方法是错误的。

  case WM_PAINT:

    return 0;

  Windows发送WM_PAINT消息是因为客户区的一部分变得无效。如果不调用BeginPaint()或ValidateRect(),则无效区域永远也不会变得有效。这样以来Windows将不停地发送WM_PAINT消息。

  程序调用BeginPaint时,Windows会适当填入PAINTSTRUCT结构的各个字段值。用户程序只使用前三个字段,其它字段由Windows内部使用。

  如果该窗口的窗口类有背景刷,BeginPaint返回前用刷子擦除无效区域的背景。HelloWin程序中的窗口类中就有背景刷:

  wndclass.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);

  在大多数情况下,fErase被标志为FALSE(0),这意味着Windows已经擦除了无效矩形的背景。如果想在窗口处理程序中自己定义一些背景的擦除行为,可以自行处理WM_ERASEBKGN消息。当fErase被标记为TRUE时BeginPaint返回前向窗口发出WM_ERASEBKGN消息。

  如果程序通过调用InvalidateRect使客户区中的矩形失效,则该函数的最后一个参数会指定是否擦除背景。如果这个参数为FALSE,则Windows将不会擦除背景,并且在调用完BeginPaint后PAINTSTRUCT结构的fErase字段将为TRUE(非零)。


  保存si.Pos变化前的值。

  if(si.nPos != iVertPos)

  经过switch语句之后,如果si.nPos的值发生了改变,上面的if语句的条件就成了TRUE,然后执行里面的:

  ScrollWindow(hwnd, 0, cyChar * (iVertPos - si.nPos), NULL, NULL);

  UpdateWindow(hwnd);

  ScrollWindow函数的功能是滚动客户区内容。假设滚动条接收到的是SB_LINEDOWN,si.nPos就会比iVertPos大,也就是说 iVertPos - si.nPos 的值是 -1,在这个时候ScrollWindow函数会把客户区的内容向上移动一行。当ScrollWindow函数的第三个参数为正数时,该函数会把客户区的内容下移。在一开始谈滚动条的时候就说过,当我们下拉滚动条的时候客户区的内容是向上移动的,一定要注意这一点。(Windows自动将显示区域中未被滚动操作覆盖的矩形设为无效,也就是将滚动所产生的空白区域设为无效。这会产生WM_PAINT消息。)

  UpdateWindow函数通知Windows立即刷新客户区。(水平滚动条部分也是同样道理。)在呼叫InvalidateRect之后,Windows将WM_PAINT消息放入消息队列中,最后由窗口消息处理程序处理它。然而,Windows将WM_PAINT消息当成低优先级消息,如果系统有许多其它的动作正在发生,那么也许会让您等待一会儿工夫。如果希望立即更新无效区域,可以在呼叫InvalidateRect之后呼叫UpdateWindow。

WM_PAINTT部分

  把垂直滚动条和水平滚动条的当前位置分别保存到iVertPos和iHorzPos中。

  现在假设,一共有75行信息(0行到74行)需要显示,客户区能显示50行(0行到49行)。滚动条原来的位置是0。

  用户把滚动条向下移动了两行,也就是说客户区的信息要向上移动两行,这个时候第0行、第1行已经看不见了,客户区顶部显示的是第2行的信息,而原来显示在客户区最后一行的第49行升到第47行了。这个时候第48行,第49行变成了空白区域。

  ps.rcPaint.top 是该空白区域的左上角坐标。

  ps.rcPaint.top / cyChar 就成了空白区域最上面一行的行数,跟据上面的假设,这是第48行。

  客户区内容上移了两行,所以原来48行的位置上应该显示第50行的内容。然后在第49行显示的是第51行的内容。现在客户区显示了第2行到第51行的内容。

  ps.rcPaint.bottom / cyChar 是空白区域最后一行的显示位置。

  iPaintBeg = max (0, iVertPos + ps.rcPaint.top / cyChar);

  iPaintEnd = min(NUMLINES - 1, iVertPos + ps.rcPaint.bottom / cyChar);

  为什么要在 ps.rcPaint.top / cyChar 前面加上iVertPos呢?

  虽然是第48行,但是要显示的内容是原来第50行的,也就是sysmetrics[50],所以要加上移动的行数iVertPos,这里iVertPos是2,所以正好能在第48行显示50行的内容。iPaintBeg与iPaintEnd也就是数组下标的开始与结束。

  进入for循环。这个时候iPaintBeg的值是50,iPaintEnd的值是52。

  y = cyChar * (i - iVertPos);

  y的值变成48,因为第50行信息的显示位置是48,然后就是使用TextOut显示文本串了。

  要显示的是第i行的内容(sysmetrics[i]),也就是第50行的内容,显示坐标y是第48行的坐标,所以程序将第50行的内容显示到第48行上,以此类推。

  for循环的条件是i <= iPaintEnd,程序实际上多显示了一行,当滚动至最底部时,i值会大于数组边界,因此要限制一下变量的赋值范围。

  x = cxChar * (1 - iHorzPos);

  x坐标初始显示位置为cxChar * (1 - iHorzPos),与SYSMETS2不一样。

转载地址:http://risli.baihongyu.com/

你可能感兴趣的文章
【一天一道LeetCode】#92. Reverse Linked List II
查看>>
【一天一道LeetCode】#93. Restore IP Addresses
查看>>
【一天一道LeetCode】#94. Binary Tree Inorder Traversal
查看>>
【一天一道LeetCode】#113. Path Sum II
查看>>
【一天一道LeetCode】#114. Flatten Binary Tree to Linked List
查看>>
【unix网络编程第三版】阅读笔记(二):套接字编程简介
查看>>
【一天一道LeetCode】#115. Distinct Subsequences
查看>>
【一天一道LeetCode】#116. Populating Next Right Pointers in Each Node
查看>>
【一天一道LeetCode】#117. Populating Next Right Pointers in Each Node II
查看>>
【一天一道LeetCode】#118. Pascal's Triangle
查看>>
【一天一道LeetCode】#119. Pascal's Triangle II
查看>>
【unix网络编程第三版】ubuntu端口占用问题
查看>>
【一天一道LeetCode】#120. Triangle
查看>>
【unix网络编程第三版】阅读笔记(三):基本套接字编程
查看>>
同步与异步的区别
查看>>
IT行业--简历模板及就业秘籍
查看>>
JNI简介及实例
查看>>
DOM4J使用教程
查看>>
JAVA实现文件树
查看>>
Drools 规则引擎
查看>>