VC实现滚动条的详解

    技术2022-05-19  17

    显示区域大小:

    我们曾经使用过 GetClientRect 函数来获取显示区域的大小,使用这个函数没有什么不好,只是效率太低,确定显示区域更好的方法是在窗口消息处理程序中处理 WM_SIZE消息。传递给窗口消息处理程序的lParam 参数的低字节包含显示区域的宽度,高字节包含高度。

    static int nxClient, nyClient;

    case WM_SIZE:

    nxClient = LOWORD(lParam);

    nyClient = HIWORD(lParam);

    return 0;

    滚动条的范围和位置:

    每个滚动条有一个相关的“范围”和“位置”,位置是一个整数序列。

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

     // iBar 为 SB_VERT 或者 SB_HORZ。如果想要 Windows 根据新范围重画滚动条,则 //设置bRedraw 为 TRUE;

    SetScrollPos(hwnd, iBar, iPos, bRedraw);

    //iPos 是设置在iMin 和 iMax 之间的整数值

    当释放鼠标按键后,程序会收到一个带有SB_ENDSCROLL通知码的消息,一般可以忽略这个消息。

    当把鼠标的光标在滑块上按鼠标时,就会产生SB_THUMBTRACK 和 SB_THUMBPOSITION 通知码的滚动条消息。当 wParam 的低字节是 SB_THUMBTRACK时,wParam 的高字节是使用者在拖动滑块时的当前位置。当 wParam 的低字节是 SB_THUMBPOSITION 时,wParam 的高字节是使用者释放滑块的最终位置。

    滚动条范围使用 32 位的值也是可以的,但是当使用了32位的时候,wParam(16位) 的高字节就不能准确获得滑块当前的位置了,这时候,需要使用 GetScrollInfo 函数来得到信息。

    OK,来写代码:

    第一步,在 CreateWindow 中添加 WS_VSCROLL 如下:

    hwnd = CreateWindow(szClsName, TEXT("Scroll Test."), WS_OVERLAPPEDWINDOW | WS_VSCROLL, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, NULL, NULL, hInstance, NULL);

    第二步,添加 WM_VSCROLL 响应:

    WM_VSCROLL:

    switch(LOWORD){wParam}

    {

    case SB_THUMBTRACK:

    nVPos = HIWORD(wParam);

    break;

    case SB_PAGEDOWN:

    nVPos += nyClient / nyChar;

    break;

    case SB_PAGEUP:

    nVPos -= nyClinet / nyChar;

    break;

    case SB_LINEDOWN:

    nVPos += 1;

    break;

    case SB_LINEUP:

    nVPos -= 1;

    break;

    }

    nVPos = max(0, min(nVPos, NUMLINES - nyClinet / nyChar));

    if(nVPos != GetScrollPos(hwnd, SB_VERT)) //滑块位置改变

    {

    SetScrollPos(hwnd, SB_VERT, nVPos, TRUE); //重设位置

    InvalidateRect(hwnd, NULL, TRUE);   //重绘显示区

    }

    第三步:添加绘制响应

    case WM_PAINT:

    hdc = BeginPaint(hwnd, &ps);

      for(i = 0; i < NUMLINES; i++)

      {

       y = nyChar * (i - nVPos);

       TextOut(hdc, 0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));

       TextOut(hdc, 22*nxCaps, y, 

        sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));

       SetTextAlign(hdc, TA_RIGHT | TA_TOP);

       TextOut(hdc, 22*nxCaps + 40*nxChar, y, 

        szBuf, wsprintf(szBuf, TEXT("%d"), GetSystemMetrics(sysmetrics[i].Index)));

       SetTextAlign(hdc, TA_LEFT | TA_TOP);

      }

    EndPaint(hwnd, &ps);

      第四步,当窗口大小发生改变时重绘

      case WM_SIZE:

    nyClient = HIWORD(lParam);

    SetScrollRange(hwnd, SB_VERT, 0, NUMLINES - nyClient / nyChar, FALSE);

    SetScrollPos(hwnd, SB_VERT, nVPos, TRUE);

    if((NUMLINES - nVPos)*nyChar < nyClient && NUMLINES * nyChar > nyClient)

    {

    nVPos = NUMLINES - nyClient / nyChar;

    //PostMessage(hwnd, WM_VSCROLL, (nVPos << 16) & SB_THUMBTRACK, 0);

    }

    ///  源码   /

    #define UNICODE UNICODE       #include <Windows.h>      #include "metrics.h"

    LRESULT CALLBACK WndProc(        HWND hwnd,      // handle to window        UINT uMsg,      // message identifier        WPARAM wParam,  // first message parameter        LPARAM lParam   // second message parameter        ) {  HDC hdc;  PAINTSTRUCT ps;  static int nxChar, nyChar, nxCaps;  static int nyClient, nVPos;  int i, y;  TCHAR szBuf[10];

     switch(uMsg)  {  case WM_CREATE:   TEXTMETRIC tm;   hdc = GetDC(hwnd);   GetTextMetrics(hdc, &tm);

      nxChar = tm.tmAveCharWidth;   nyChar = tm.tmHeight + tm.tmExternalLeading;   nxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * nxChar / 2 ;   ReleaseDC(hwnd, hdc);

     case WM_PAINT:   hdc = BeginPaint(hwnd, &ps);   for(i = 0; i < NUMLINES; i++)   {    y = nyChar * (i - nVPos);    TextOut(hdc, 0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));    TextOut(hdc, 22*nxCaps, y,     sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));

       SetTextAlign(hdc, TA_RIGHT | TA_TOP);    TextOut(hdc, 22*nxCaps + 40*nxChar, y,     szBuf, wsprintf(szBuf, TEXT("%d"), GetSystemMetrics(sysmetrics[i].Index)));    SetTextAlign(hdc, TA_LEFT | TA_TOP);   }   EndPaint(hwnd, &ps);   return 0;  case WM_SIZE:     nyClient = HIWORD(lParam);   SetScrollRange(hwnd, SB_VERT, 0, NUMLINES - nyClient / nyChar, FALSE);   SetScrollPos(hwnd, SB_VERT, nVPos, TRUE);   if((NUMLINES - nVPos)*nyChar < nyClient && NUMLINES * nyChar > nyClient)   {    nVPos = NUMLINES - nyClient / nyChar;    //PostMessage(hwnd, WM_VSCROLL, (nVPos<<16) & SB_THUMBTRACK,0);   }   return 0;  case WM_VSCROLL:   switch(LOWORD(wParam))   {   case SB_THUMBTRACK:    nVPos = HIWORD(wParam);    break;   case SB_PAGEDOWN:    nVPos += nyClient / nyChar;    break;   case SB_PAGEUP:    nVPos -= nyClient / nyChar;    break;   case SB_LINEDOWN:    nVPos += 1;    break;   case SB_LINEUP:    nVPos -= 1;    break;   }   nVPos = max(0, min(nVPos, NUMLINES - nyClient / nyChar));   if(nVPos != GetScrollPos(hwnd, SB_VERT))   {    SetScrollPos(hwnd, SB_VERT, nVPos, TRUE);    InvalidateRect(hwnd, NULL, TRUE);   }   return 0;  case WM_CLOSE:   DestroyWindow(hwnd);  case WM_DESTROY:   PostQuitMessage(0);   return 0;  }  return DefWindowProc(hwnd, uMsg, wParam, lParam); }

    int WINAPI WinMain(        HINSTANCE hInstance,      // handle to current instance        HINSTANCE hPrevInstance,  // handle to previous instance        LPSTR lpCmdLine,          // command line        int nCmdShow              // show state        ) {  static TCHAR szClsName[] = TEXT("HelloWin");  HWND hwnd;  MSG msg;  WNDCLASS cls;    cls.cbClsExtra = 0;  cls.cbWndExtra = 0;  cls.hbrBackground = (HBRUSH)GetStockObject(WHITE_BRUSH);  cls.hCursor = LoadCursor(NULL, IDC_ARROW);  cls.hIcon = LoadIcon(NULL, IDI_APPLICATION);  cls.hInstance = hInstance;  cls.lpfnWndProc = WndProc;  cls.lpszClassName = szClsName;  cls.lpszMenuName = NULL;  cls.style = CS_VREDRAW | CS_HREDRAW;    if(!RegisterClass(&cls))  {   MessageBox(NULL, TEXT("This program requires Windows NT!"),    szClsName, MB_ICONERROR);   return 0;  }    hwnd = CreateWindow(szClsName, TEXT("Bing's Pad"), WS_OVERLAPPEDWINDOW | WS_VSCROLL,   CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT, CW_USEDEFAULT,   NULL, NULL, hInstance, NULL);    ShowWindow(hwnd, nCmdShow);  UpdateWindow(hwnd);    while(GetMessage(&msg,NULL,0,0))  {   TranslateMessage(&msg);   DispatchMessage(&msg);  }    return msg.wParam; }


    最新回复(0)