现在的位置: 首页 > 综合 > 正文

VC实现滚动条的详解

2013年02月27日 ⁄ 综合 ⁄ 共 5431字 ⁄ 字号 评论关闭

显示区域大小

我们曾经使用过 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 函数来得到信息。

VC实现滚动条的详解 - DH冰 - //... DH冰的安全笔记

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

抱歉!评论已关闭.