• 深入探索ScrollWindow


    最近做WIN32 API开发时发现对ScrollWindow的一些工作原理并不是太清楚,于是做了相关研究,记载下来和大家共同学习。

    首先在WM_CREATE中获取系统字符的宽度和高度

    [cpp] view plain copy
     
     print?
    1. case WM_CREATE:  
    2.         //获取系统字符的宽度和高度  
    3.         cxChar = LOWORD(GetDialogBaseUnits()) ;  
    4.         cyChar = HIWORD(GetDialogBaseUnits()) ;  
    5.   
    6.         //显示字体大小  
    7.         sprintf(szBuffer, TEXT("字符高度:%d 字符宽度:%d"), cyChar, cxChar) ;  
    8.         MessageBox(hwnd, szBuffer, TEXT("字符大小"), MB_OK) ;  
    9. return 0 ;  

    再在WM_SIZE中获取客户区大小

    [cpp] view plain copy
     
     print?
    1. case WM_SIZE:  
    2.     //获取客户区大小  
    3.     GetClientRect(hwnd, &rcClient) ;  
    4.   
    5.     //显示客户区大小  
    6.     sprintf(szBuffer, TEXT("左上角:%d %d 右下角:%d %d"), rcClient.left, rcClient.top, rcClient.right, rcClient.bottom) ;  
    7.     MessageBox(hwnd, szBuffer, TEXT("客户区大小"), MB_OK) ;  
    8. return 0 ;  

    为了增强滚动时的对比效果,在WM_PAINT中分别写左右两行文字

    [cpp] view plain copy
     
     print?
    1. case WM_PAINT:  
    2.     hdc = BeginPaint (hwnd, &ps) ;  
    3.   
    4.     //获取重画区域大小  
    5.     sprintf(szBuffer, TEXT("%d %d %d %d"), ps.rcPaint.left, ps.rcPaint.top, ps.rcPaint.right, ps.rcPaint.bottom) ;  
    6.     MessageBox(hwnd, szBuffer, TEXT("重画区域"), MB_OK) ;  
    7.   
    8.     TextOut(hdc, 0, (rcClient.bottom-rcClient.top)/2,   
    9.         TEXT("Text Out here left!"), lstrlen(TEXT("Text Out here left!"))) ;  
    10.     TextOut(hdc, (rcClient.right-rcClient.left)/2, (rcClient.bottom-rcClient.top)/2,   
    11.         TEXT("Text Out here right!"), lstrlen(TEXT("Text Out here right!"))) ;  
    12.   
    13.     EndPaint (hwnd, &ps) ;  
    14.   
    15. return 0 ;  

    下面再加上滚动右边文字的代码

    [cpp] view plain copy
     
     print?
    1. case WM_KEYDOWN:  
    2.         CopyRect(&rect, &rcClient) ;  
    3.         rect.left = rcClient.right / 2 ;  
    4.   
    5.         switch(wParam)  
    6.         {  
    7.             case VK_DOWN:  
    8.                 ScrollWindow(hwnd, 0, cyChar, &rect, &rect) ;  
    9.                 break ;  
    10.             case VK_UP:  
    11.                 ScrollWindow(hwnd, 0, -cyChar, &rect, &rect) ;  
    12.                 break ;  
    13.         }  
    14. return 0 ;  


    运行依次进入WM_CREATE,WM_PAINT,WM_SIZE消息

    WM_CREATE中显示

    WM_PAINT中显示

    WM_SIZE中显示

    可知

    字符大小为高度16px    宽度8px

    客户区大小为宽1009px    高488px

    左边显示区域范围为左0px    上0px    右504px    下488px 

    右边显示区域范围为左504px    上0px    右1009px    下488px 

    按小键盘上的上下滚动键分别得到重绘区域为

    对比计算

    可知当使用ScrollWindow时左边区域并没有重绘 

    当右边向上滚动时 重绘区域为向上滚动后没有被滚动区域覆盖的最小面一行字符区域

    当右边向下滚动时 重绘区域为向下滚动后没有被滚动区域覆盖的最上面一行字符区域

    故 我们再看看微软MSDN中对ScrollWindow的描述

    “如果在被滚动的窗口中含有^符,ScrollWindow将自动隐藏起^符,以防它被擦掉;当滚动结束后再恢复^符。^符的位置相应的被调整过来。  

    未被ScrollWindow覆盖的区域不再重画,但该区域会与窗口更新区域组合。应用程序最终收到WM_PAINT的消息,通知它结合区域必须被重画。为了在滚动操作的同时重画未覆盖区域,则应在调用ScrollWindow函数后马上调用UpdateWindow函数。  

    如果参数lpRect为NULL,则窗口中的任何子窗口的位置由参数XAmount和Yamount的数值决定偏移;窗体无效(未着色)的区域也偏移。IpRect为NULL时ScrollWindow执行地更快。  

    如果参数lpRect不为NULL,则窗口中的子窗口的位置不改变,窗口中无效(未着色)的区域也不偏移。为了防止lpRect不为NULL时更新的问题,需要在调用ScrollWindow前调用UpdateWindow函数重绘窗口。”

    这里的未被scrollWindow覆盖的区域应该强调是scrollWindow使用的剪切区域中未被滚动操作覆盖的区域,这里是很多人难以理解的地方,务必注意。

    那么如何高效的使用ScrollWindow这个API函数呢

    这里笔者以每次滚动一行文字为例,提供两种方法

    1.按照MSDN提供的方法来使用

    调用完ScrollWindow后 ,立即调用UpdateWindow发送一个不进队的WM_PAINT消息。在WM_PAINT消息中可以按照滚动时的逻辑,整个区域都绘制但是利用重绘区域自动将多余的绘制剪切掉,只绘制未被滚动操作覆盖的一行;但是更高明的做法无疑是只绘制未被滚动操作覆盖的一行,加快绘制速度。

    2.在调用ScrollWindow的非WM_PAINT消息中绘制

    在调用按ScrollWindow后获得窗口DC,自己绘制未被滚动操作覆盖的一行,然后将整个滚动剪切区域设为有效,禁止其产生WM_PAINT消息,这样也可加快绘制速度。

    原创,转载请注明来自http://blog.csdn.net/wenzhou1219

    http://blog.csdn.net/wenzhou1219/article/details/7798967

  • 相关阅读:
    验证回文串
    03-Python控制语句
    02-Python运算符
    ACwing(基础) --- Bellman-Ford&SPFA
    ACwing(基础)--- Dijkstra算法(含堆优化版)
    ACwing(基础)--- 区间合并
    ACwing(基础)--- 位运算
    ACwing(基础)--- 双指针算法
    ACwing(基础)--- 高精度
    ACwing(基础)---790. 数的三次方根
  • 原文地址:https://www.cnblogs.com/findumars/p/6329645.html
Copyright © 2020-2023  润新知