旅途

如果想飞得高,就该把地平线忘掉

滚动条

LRESULT CALLBACK WndProc (HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
       
{
       
    static int  cxChar, cxCaps, cyChar, cyClient, iVscrollPos ;
       
    HDC         hdc ;   
       
    int         i, y ;  
       
    PAINTSTRUCT ps ;
       
    TCHAR       szBuffer[10] ;  
       
    TEXTMETRIC  tm ;    
       
    switch (message)    
       
    {
       
case WM_CREATE:
       
    hdc = GetDC (hwnd) ;
       
    GetTextMetrics (hdc, &tm) ;
       
    cxChar = tm.tmAveCharWidth ;
       
    cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2 ;
       
    cyChar = tm.tmHeight + tm.tmExternalLeading ;
       

    ReleaseDC (hwnd, hdc) ;
       
    SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE) ;
       
    SetScrollPos   (hwnd, SB_VERT, iVscrollPos, TRUE) ;
       
            return 0 ;
       

    case WM_SIZE:
       
            cyClient = HIWORD (lParam) ;
       
            return 0 ;
       

    case WM_VSCROLL:
       
            switch (LOWORD (wParam))
       
         {
       
    case SB_LINEUP:
       
          iVscrollPos -= 1 ;
       
            break ;
       
  
       
    case SB_LINEDOWN:
       
            iVscrollPos += 1 ;
       
            break ;
       

    case SB_PAGEUP:
       
            iVscrollPos -= cyClient / cyChar ;
       
            break ;
       
  
       
    case SB_PAGEDOWN:
       
            iVscrollPos += cyClient / cyChar ;
       
            break ;
       
  
       
    case SB_THUMBPOSITION:
       
            iVscrollPos = HIWORD (wParam) ;
       
            break ;
       
  
       
    default :
       
            break ;
       
         }
       

    iVscrollPos = max (0, min (iVscrollPos, NUMLINES - 1)) ;
       
    if (iVscrollPos != GetScrollPos (hwnd, SB_VERT))
       
         {
       
            SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
       
            InvalidateRect (hwnd, NULL, TRUE) ;
       
         }
       
            return 0 ;
       
    case WM_PAINT:
       
            hdc = BeginPaint (hwnd, &ps) ;
       
            for (i = 0 ; i < NUMLINES ; i++)
       
            {
       
                   y = cyChar * (i - iVscrollPos) ;
       
                   TextOut (hdc, 0, y,
       
                           sysmetrics[i].szLabel,
       
                           lstrlen (sysmetrics[i].szLabel)) ;
       
  
       
                   TextOut (hdc, 22 * cxCaps, y,
       
                           sysmetrics[i].szDesc,
       
                           lstrlen (sysmetrics[i].szDesc)) ;
       
  
       
                   SetTextAlign (hdc, TA_RIGHT | TA_TOP) ;
       
                   TextOut (hdc, 22 * cxCaps + 40 * cxChar, y, szBuffer,
       
                           wsprintf (szBuffer, TEXT ("%5d"),
       
                                          GetSystemMetrics (sysmetrics[i].iIndex))) ;
       
                   SetTextAlign (hdc, TA_LEFT | TA_TOP) ;
       
        }
       
            EndPaint (hwnd, &ps) ;
       
            return 0 ;
       

    case WM_DESTROY:
       
            PostQuitMessage (0) ;
       
            return 0 ;
       
    }
       
    return DefWindowProc (hwnd, message, wParam, lParam) ;
       
}


WndProc窗口消息处理程序在处理WM_CREATE消息时增加了两条叙述,以设置垂直滚动条的范围和初始位置:
SetScrollRange (hwnd, SB_VERT, 0, NUMLINES - 1, FALSE) ;
       
SetScrollPos (hwnd, SB_VERT, iVscrollPos, TRUE) ;
具有NUMLINES行文字,所以滚动条范围被设定为0至NUMLINES-1。滚动条的每个位置对应于在显示区域顶部显示的一个文字行。如果卷动方块的位置为0,则第一行会被放置在显示区域的顶部。如果位置大于0,其它行就会出现在显示区域的顶部。当位置为NUMLINES-1时,则最后一行文字出现在显示区域的顶部。

为了有助于处理WM_VSCROLL消息,在窗口消息处理程序中定义了一个静态变量iVscrollPos,这一变量是滚动条内卷动方块的目前位置。对于SB_LINEUP和SB_LINEDOWN,只需要将卷动方块调整一个单位的位置。对于SB_PAGEUP和SB_PAGEDOWN,我们想移动一整面的内容,或者移动cyClient /cyChar个单位的位置。对于SB_THUMBPOSITION,新的卷动方块位置是wParam的高字组。SB_ENDSCROLL和SB_THUMBTRACK消息被忽略。


在程序依据收到的WM_VSCROLL消息计算出新的iVscrollPos值后,用min和max宏来调整iVscrollPos,以确保它在最大值与最小值之间。程序然后将iVscrollPos与呼叫GetScrollPos取得的先前位置相比较,如果卷动位置发生了变化,则使用SetScrollPos来进行更新,并且呼叫InvalidateRect使整个窗口无效


InvalidateRect呼叫产生一个WM_PAINT消息。

在处理完滚动条消息后,不更新显示区域,相反,它呼叫InvalidateRect使显示区域失效。这导致Windows将一个WM_PAINT消息放入消息队列中。
最好能使Windows程序在响应WM_PAINT消息时完成所有的显示区域绘制功能。因为程序必须在一接收到WM_PAINT消息时就更新整个显示区域,如果在程序的其它部分也绘制的话,将很可能使程序代码重复。


 

只将窗口显示区域标记为无效以产生WM_PAINT消息,对于某些应用程序来说也许不是完全令人满意的选择。在呼叫InvalidateRect之后,Windows将WM_PAINT消息放入消息队列中,最后由窗口消息处理程序处理它。然而,Windows将WM_PAINT消息当成低优先级消息,如果系统有许多其它的动作正在发生,那么也许会让您等待一会儿工夫。这时,当对话框消失时,将会出现一些空白的「洞」,程序仍然等待更新它的窗口。

如果您希望立即更新无效区域,可以在呼叫InvalidateRect之后呼叫UpdateWindow:

UpdateWindow (hwnd) ;

如果显示区域的任一部分无效,则UpdateWindow将导致Windows用WM_PAINT消息呼叫窗口消息处理程序(如果整个显示区域有效,则不呼叫窗口消息处理程序)。这一WM_PAINT消息不进入消息队列,直接由Windows呼叫窗口消息处理程序。窗口消息处理程序完成更新后立即退出,Windows将控制传回给程序中UpdateWindow呼叫之后的叙述。




 

posted on 2007-06-12 21:41 旅途 阅读(672) 评论(0)  编辑 收藏 引用 所属分类: window读书笔记


只有注册用户登录后才能发表评论。
网站导航: 博客园   IT新闻   BlogJava   知识库   博问   管理