加入滚动条

同样头文件还是原来的头文件。

源文件:

/*----------------------------------------------------
   SYSMETS2.C -- System Metrics Display Program No. 2
                 (c) Charles Petzold, 1998
  ----------------------------------------------------*/

#define WINVER 0x0500
#include <windows.h>
#include "sysmets.h"
 
LRESULT CALLBACK WndProc (HWND, UINT, WPARAM, LPARAM) ;

int WINAPI WinMain (HINSTANCE hInstance, HINSTANCE hPrevInstance,
                    PSTR szCmdLine, int iCmdShow)
{
     static TCHAR szAppName[] = TEXT ("SysMets2") ;
     HWND         hwnd ;
     MSG          msg ;
     WNDCLASS     wndclass ;

     wndclass.style         = CS_HREDRAW | CS_VREDRAW ;
     wndclass.lpfnWndProc   = WndProc ;
     wndclass.cbClsExtra    = 0 ;
     wndclass.cbWndExtra    = 0 ;
     wndclass.hInstance     = hInstance ;
     wndclass.hIcon         = LoadIcon (NULL, IDI_APPLICATION) ;
     wndclass.hCursor       = LoadCursor (NULL, IDC_ARROW) ;
     wndclass.hbrBackground = (HBRUSH) GetStockObject (WHITE_BRUSH) ;
     wndclass.lpszMenuName  = NULL ;
     wndclass.lpszClassName = szAppName ;

     if (!RegisterClass (&wndclass))
     {
          MessageBox (NULL, TEXT ("This program requires Windows NT!"), 
                      szAppName, MB_ICONERROR) ;
          return 0 ;
     }

     hwnd = CreateWindow (szAppName, TEXT ("Get System Metrics No. 2"),
                          WS_OVERLAPPEDWINDOW | WS_VSCROLL,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          CW_USEDEFAULT, CW_USEDEFAULT,
                          NULL, NULL, hInstance, NULL) ;

     ShowWindow (hwnd, iCmdShow) ;
     UpdateWindow (hwnd) ;

     while (GetMessage (&msg, NULL, 0, 0))
     {
          TranslateMessage (&msg) ;
          DispatchMessage (&msg) ;
     }
     return msg.wParam ;
}

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) ;
}

在应用程序中加入滚动条相当容易,只需在 CreateWindow() 函数的第三个参数中包括窗口风格标识符 

WS_VSCROLL(垂直滚动条) 或 WS_HSCROLL(水平滚动条), 或者同时包括两者。

在 CreateWindow() 函数中指定的滚动条总是出现在窗口的右边和底部,而且总是伸展到整个客户区的宽度和高度。

客户区并不包含滚动条所占用的空间。

扫描二维码关注公众号,回复: 1750621 查看本文章

Windows负责处理滚动条中所有鼠标消息。但是,滚动条并没有自动对应的键盘接口。

如果想将方向键对应到滚动条上,则必须显示的提供相应的对应关系。

每个滚动条都有相应的"范围"和"位置"。滚动条的范围是一对整数,分别代表滚动条的最小值和最大值。

位置是指滑块在范围中所处的值。当滑块在滚动条的顶端时,滑块的位置是范围的最小值。相应的,

当滑块在滚动条的底部(或最右)时,位置是范围最大值。

在默认情况下,滚动条的范围是 1~100,不过通过下面的函数调用,可以很方便的把范围改成对程序更有意义的值:

SetScrollRange(hwnd, iBar, iMin, iMax, bRedraw);

这里的 iBar 参数要么是 SB_VERT(垂直滚动条范围), 要么是 SB_HORZ(水平滚动条范围), 用来指定滚动条将被设置。

而 iMin 和 iMax 分别对应范围的最小值和最大值。


需要 Windows 根据新的范围来重绘滚动条时,请将 bRedraw 参数设为 TRUE, (如果在调用 SetScrollRange() 函数

之后还调用其他函数来调整滚动条的显示时,最好将bRedraw 设为 FALSE 以避免过多的重绘)。

通过 SetScrollPos() 函数调用即可指定滑块在滚动条范围中的位置:

SetScrollPos(hwnd, iBar, iPos, bRedraw);

这里的参数 iPos 是滑块的新位置,他必须在 iMin 和 iMax 之间。 Windows 提供了两个类似的函数

GetScrollRange() 和 GetScrollPos() 用于获取滚动条的当前范围和位置。

另外,在程序中使用滚动条时,程序需要和 Windows 共同负责维护滚动条以及滑块在滚动条中的位置。

请记住以下几点:

Windows 负责如下任务:

  • 处理滚动条中所有鼠标消息
  • 当用户单击滚动条时,提供一种反向显示的闪烁
  • 当用户拖动滑块时,在滚动条内移动滑块
  • 向拥有滚动条的窗口的窗口过程(WndProc() )发送滚动条消息
程序需要负责如下任务:
  • 初始化滚动条的范围和位置
  • 处理传送给窗口过程的滚动条消息
  • 更新滑块的位置
  • 根据滚动条的变化更新客户区的内容
而对于 WM_SIZE 消息,只要当窗口的大小发生变化时,Windows 会向窗口过程发送一条 WM_SIZE 消息。

相应的 lParam 变量的低位是客户区的宽度,而高位自然就是高度。

可以这样处理 WM_SIZE 消息:

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


滚动条消息:

当用户单击滚动条或拖到滚动条时,Windows 向窗口过程发送 WM_VSCROLL 消息(垂直滚动)或 WM_HSCROLL(水平滚动)。

在滚动条的上的任何鼠标动作会产生至少两条消息,一条在鼠标按下时,另一条在鼠标键松开时。

就像所有消息一样,WM_VSCROLL 和 WM_HSCROLL 消息都伴随着 wParam 和 lParam 消息参数。

当滚动条是窗口一部分时,可以忽略 lParam 参数:它只用于滚动条是子窗口时,通常是在对话框中。

同样 wParam 参数也被分为低位字和高位字。低位字代表了鼠标在滚动条上的动作。这个值被称为"通知码"。

由一个以 SB 开头的标识符定义(SB 代表滚动条)。

下面是在 WINUSER.H 中定义的通知码:

#define SB_LINEUP 0
#define SB_LINELEFT 0
#define SB_LINEDOWN 1
#define SB_LINERIGHT 1
#define SB_PAGEUP 2
#define SB_PAGELEFT 2
#define SB_PAGEDOWN 3
#define SB_PAGERIGHT 3
#define SB_THUMBPOSITION 4
#define SB_THUMBTRACK 5
#define SB_TOP 6
#define SB_LEFT 6
#define SB_BOTTOM 7
#define SB_RIGHT 7
#define SB_ENDSCROLL 8

凡是含有 LEFT, RIGHT 的标识符用于水平滚动条中,而含有 UP, DOWN, TOP, BOTTOM 的标识符用于垂直滚动条中。

当松开鼠标键时,程序会收到 SB_ENDSCROLL 消息。

将鼠标放在滑块上然后按下鼠标键时,可以移动滑块。这将会产生带 SB_THUMBPOSITION 和 SB_THUMBTRACK 

通知码的滚动消息。当 wParam 的低位字是 SB_THUMBTRACK 时,它的高位字便是用户拖动滑块的当前位置。

如果低位字是 SB_THUMBPOSITION 时,它的高位字便是用户松开鼠标键时滑块的最终位置。

可以看下图加深理解:





好了,现在程序应该可以看懂了吧!

不过该程序有缺陷,因为它没有处理鼠标在拖动滑块的过程中对客户区的重绘!

下节将进一步完善。



猜你喜欢

转载自blog.csdn.net/qq_41413835/article/details/80766484
今日推荐