3.2 窗口滚动条

本节讲述窗口滚动条的简单使用方法。如果窗口客户区的内容太多,为了方便浏览窗口客户区的所有内容,就需要在创建窗口时添加窗口垂直或水平滚动条样式。窗口过程处理WM_CREATE消息时初始化滚动条的位置和滚动范围。窗口过程处理WM_VSCROLL或WM_HSCROLL消息时响应滚动条的操作,改变滚动条滑块的位置。

本节必须掌握的知识点:

        滚动条

        第20练:简单的窗口滚动条

3.2.1 滚动条

滚动条

在Windows系统中,滚动条(Scrollbar)是一种常见的用户界面元素,用于在有限的显示区域中查看较大的内容。滚动条通常出现在窗口的右侧和底部,用户可以通过点击或拖动滚动块(Thumb)来查看不同部分的内容。既可以用鼠标单击滚动条两端的箭头,也可以单击箭头之间的区域。一个“滑块”在滚动条中移动,表明当前显示的内容在整个文档中的大概位置。可以用鼠标拖动滑块到特定的位置。

程序员和用户看待滚动条的角度不同,当用户向下滚动时,实际是程序将文件相对于显示窗口向上移动。windows文档和头文件中的标识符都是从用户的角度出发:向上滚动意味着移向文档的开始,而向下滚动意味着移向文档的结束。

在Windows编程中,你可以通过几种方式来为窗口添加滚动条:

       1.将滚动条作为窗口的一部分,在创建窗口(CreateWindow)时添加滚动条。这是本章将要实现的滚动条。

       2.将滚动条作为一个独立的子窗口,添加滚动条子窗口控件。我们将在第八章讲解滚动条子窗口控件。

滚动条的范围和位置

每个滚动条都有相应地“范围”和“位置”。滚动条的范围是一对整数,分别代表滚动条的最小值和最大值。位置是指滑块在范围中所处的值。当滑块在滚动条的顶端(或最左)时,滑块的位置是范围的最小值。相应的,当滑块在滚动条的底部(或最右)时,位置是范围的最大值。在默认状态下,滚动条的范围是0~100。

在Windows编程中,可以使用一组API函数来管理窗口滚动条的范围(即滚动条能代表的最大最小值)和位置(即滚动条滑块当前表示的值)。

1.设置滚动条范围:使用SetScrollRange函数,可以设定滚动条可以表示的最小值和最大值。

BOOL SetScrollRange(

  HWND hWnd,

  int  nBar,

  int  nMinPos,

  int  nMaxPos,

  BOOL bRedraw

);

这个函数将滚动条的最小位置值设置为nMinPos,最大位置值设置为nMaxPos。nBar参数指定设置哪一个滚动条,如果是水平滚动条,则传入SB_HORZ,垂直滚动条则传入SB_VERT。

       2.获取滚动条范围:使用GetScrollRange函数,可以获取滚动条当前的最小值和最大值。

BOOL GetScrollRange(

  HWND hWnd,

  int  nBar,

  LPINT lpMinPos,

  LPINT lpMaxPos

);

3.设置滚动条当前位置:使用SetScrollPos函数。

int SetScrollPos(

  HWND hWnd,

  int  nBar,

  int  nPos,

  BOOL bRedraw

);

这个函数将滚动条的当前位置设置为nPos。nBar参数指定设置哪一个滚动条,如果是水平滚动条,则传入SB_HORZ,垂直滚动条则传入SB_VERT。如果bRedraw参数为TRUE,则滚动条会被立即重绘。

4.获取滚动条当前位置:使用GetScrollPos函数。

int GetScrollPos(

  HWND hWnd,

  int  nBar

);

上述涉及到的所有函数的hWnd参数都是要控制滚动条的那个窗口的句柄。

在使用滚动条时,一个常见的模式是,在响应滚动条相关的Windows消息(如WM_SCROLL)时,获取和设置滚动条的位置。滚动条的位置信息经常用于决定窗口内容的绘制,以实现在大尺寸内容上滑动查看的效果。

Windows负责如下任务

●处理滚动条中的所有鼠标消息。

●当使用者单击管道条时,提供一种反向显示的闪烁。

●当使用者拖动滚动块时,在滚动条内移动滚动块。

●向拥有滚动条的窗口的窗口过程发送滚动条消息。

■程序需要负责的任务:

●初始化滚动条的范围和位置 。

●处理传送给窗口过程的滚动条消息 。

●更新滚动块的位置 。

●根据滚动条的变化更新客户区的内容 。

滚动条消息

当用户单击滚动条或拖动滑块时,Windows向窗口过程发送WM_VSCROLL消息或WM_HSCROLL消息,分别用于处理水平和垂直滚动条的操作。这些消息通常产生于用户直接互动,如拖动滚动条的滑块,点击滚动条的箭头等。

这两个消息的格式如下:

WM_HSCROLL

WM_VSCROLL

wParam = LOWORD(wParam)   //(action)通知码

         HIWORD(wParam)   //滑块当前的位置

lParam = hwndScrollBar //跟踪条控件的句柄。如果为NULL,则消息由滚动条控件发送。

两个消息的参数中,wParam的低字节(LOWORD)表示具体的滚动操作(action),可以是以下的一些常数:

SB_LINEUP 或 SB_LINELEFT:向上或向左滚动一行。

SB_LINEDOWN 或 SB_LINERIGHT:向下或向右滚动一行。

SB_PAGEUP 或 SB_PAGELEFT:向上或向左滚动一页面。

SB_PAGEDOWN 或 SB_PAGERIGHT:向下或向右滚动一页面。

SB_THUMBPOSITION:滑块(thumb)已经拖动到新的位置,只有当用户释放滑块时才会发送。

SB_THUMBTRACK:滑块(thumb)正在被拖动。

当收到滚动条消息时,应用程序通常会在其消息处理函数中(WndProc函数),根据wParam的值进行相应的处理。这可能包括调用GetScrollPos获取当前滚动位置,调整内容的显示,然后使用SetScrollPos设置新的滚动位置。

3.2.2 第20练:简单的窗口滚动条

/*---------------------------------------------------------

SYSMETS.H -- 系统配置信息结构数组

-----------------------------------------------------------*/

#define NUMLINES ((int) (sizeof sysmetrics / sizeof sysmetrics [0]))

//结构数组

struct

{

     int iIndex;    //索引

     TCHAR * szLabel;//系统信息

     TCHAR * szDesc;//描述

}

(略)

/*------------------------------------------------------------------------

 020 编程达人win32 API每日一练

     第20个例子SYSMETS2.C:获取系统配置信息2---带滚动条的窗口   

     WM_VSCROLL消息

     SetScrollRange函数

     SetScrollPos函数

局限:1、超出滚动范围;

     2、滑块大小和客户区不成比例

     3、拖动滑块,没有实时滚动客户区

 (c) www.bcdaren.com 编程达人

-----------------------------------------------------------------------*/

#include <windows.h>

#include <tchar.h>

#include "sysmets.h" //定义系统信息结构数组及NUMLINES(显示行数)

LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM);

int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE hPrevInstance,

     PSTR szCmdLine, int iCmdShow)

{

     static TCHAR szAppName[] = TEXT("SysMets1");

    (略)

     hwnd = CreateWindow(szAppName, TEXT("Get System Metrics No. 1"),

          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;

     static int cyClient;     //新的客户区高度

     static int iVscrollPos//滚动条滑块位置,默认值0~100之间

     HDC hdc;

     int i,y;

     PAINTSTRUCT ps;

     TCHAR szBuffer[10];

     TEXTMETRIC tm;//存储装置字体结构信息

     switch (message)

     {

     case WM_CREATE:

          hdc = GetDC(hwnd);  //获取设备环境句柄

//把程序当前的字体信息,存放到TEXTMETRIC结构变量中

          GetTextMetrics(hdc, &tm);

          cxChar = tm.tmAveCharWidth;//字符平均宽度

          //tm.tmPitchAndFamily字体间距,tmPitchAndFamily字段的低位决定字体是否

//为等宽字体:1代表变宽字体,0代表等宽字体。

          //字体间距cxCaps设为cxChar的1.5倍。1表示变宽字体

          cxCaps = (tm.tmPitchAndFamily & 1 ? 3 : 2) * cxChar / 2;

          //字符行距=字符高+字符顶部空间的数目

          cyChar = tm.tmHeight + tm.tmExternalLeading;

          ReleaseDC(hwnd, hdc);//释放设备环境句柄

          //设置所指定滚动条范围的最小值和最大值。

          //SB_VERT垂直滚动调,FALSE不立即重绘滚动条,标准滚动条的默认范围是0到

//100,nMaxPos = -1,表示默认值

          SetScrollRange(hwnd, SB_VERT, 0, NUMLINES - 1, FALSE);

          //设置所指定滚动条中的滚动按钮的位置。

          SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);//TRUE重绘

          return 0;

     case WM_SIZE:

          cyClient = HIWORD(lParam);//客户区的新高度

          return 0;

      //当窗口的标准垂直滚动条中有滚动的事件发生时,操作系统捕捉到后发送

//WM_VSCROLL到消息队列,然后GetMessage消息循环从消息队列中取出消息,并//DispatchMessage分发给操作系统调用WndProc。

//此实例暂时未处理键盘按键操作滚动条的消息

     case WM_VSCROLL:

          switch (LOWORD(wParam))//wParam低16位是滚动条值

          {

          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);//wParam高16位则指定滚动框的当前位

               break;

          default:

               break;

          }

          //更新滑块位置,滑块位置在0~NUMLINES - 1之间

          iVscrollPos = max(0, min(iVscrollPos, NUMLINES - 1));

          //如果与当前滚动条滑块的位置不相等,重新设置滑块位置并重绘

          if (iVscrollPos != GetScrollPos(hwnd, SB_VERT))

          {

              SetScrollPos(hwnd, SB_VERT, iVscrollPos, TRUE);//重新设置滑块位置

               InvalidateRect(hwnd, NULL, TRUE);//并擦除背景

               UpdateWindow(hwnd);//立即更新

          }

          return 0;

     case WM_PAINT:

          hdc = BeginPaint(hwnd, &ps);

            (略)

          EndPaint(hwnd, &ps);

          return 0;

     case WM_DESTROY:

          PostQuitMessage(0);

          return 0;

     }

     return DefWindowProc(hwnd, message, wParam, lParam);

}

/******************************************************************************

WM_VSCROLL消息:当窗口的标准垂直滚动条中有滚动的事件发生时,在我们的窗口应用程序的消息队列中将产生一条WM_VSCROLL消息。

参数解释:

wParam

HIWORD指定在滚动框的当前位置

LOWORD是SB_THUMBPOSITION或SB_THUMBTRACK; 否则,将不使用该词。

LOWORD做为指定一个滚动条值,指出用户的滚动要求。这个参数可以是下列值之一。

SB_PAGEDOWN 向下滚动一页

SB_LINEDOWN 向下滚动一行

SB_PAGEUP 向上滚动一页

SB_LINEUP 向上滚动一行

SB_TOP 滚动到顶端

SB_BOTTOM 滚动到底部

SB_THUMBPOSITION 用户有拖动滚动框 (滑块),并释放鼠标按钮。HIWORD 指示在拖动操作结束时滚动框的位置。

SB_THUMBTRACK 用户正在拖动滚动框。直到用户释放鼠标按钮,反复发送此邮件。HIWORD 指示滚动框已被拖动到的位置。

lParam

如果lParam参数等于0,就说明它是窗口滚动条;如果等于滚动条窗口句柄,就说明它是滚动条控件。

返回值:如果应用程序处理此消息,则应返回零。

【备注】

SB_THUMBTRACK请求代码通常由在用户拖动滚动框时提供反馈的应用程序使用。

如果应用程序滚动窗口的内容,则它还必须使用SetScrollPos函数重置滚动框的位置。

请注意,WM_VSCROLL消息仅携带16位滚动框位置数据。因此,仅依靠WM_VSCROLL(和WM_HSCROLL)

获取滚动位置数据的应用程序实际的最大位置值为65,535。

但是,由于SetScrollInfo,SetScrollPos,SetScrollRange,GetScrollInfo,GetScrollPos

和GetScrollRange函数支持32位滚动条位置数据,因此有一种方法可以绕开WM_HSCROLL和WM_VSCROLL消息的16位障碍。

有关该技术的说明,请参见GetScrollInfo。

*******************************************************************************

SetScrollRange函数:设置所指定滚动条范围的最小值和最大值。

BOOL SetScrollRange(

  HWND hWnd, //处理滚动条控件或具有标准滚动条的窗口,具体取决于nBar参数的值 。

  int  nBar,   //指定要设置的滚动条。此参数可以是以下值之一。

               //SB_CTL设置滚动条控件的范围。该 HWND参数必须是句柄滚动条控制。

               //SB_HORZ设置窗口的标准水平滚动条的范围。

               //SB_VERT设置窗口的标准垂直滚动条的范围。

  int  nMinPos,//指定最小滚动位置。

  int  nMaxPos,//指定最大滚动位置。

  BOOL bRedraw//指定是否应重绘滚动条以反映更改。如果此参数为TRUE,则会重新绘制滚动条。如果为FALSE,则不会重画滚动条。

);

返回值

类型:布尔

如果函数成功,则返回值为非零。

如果函数失败,则返回值为零。要获取扩展的错误信息,请调用GetLastError。

【备注】

通过将nMinPos和 nMaxPos设置为相同的值,可以使用SetScrollRange隐藏滚动条 。

应用程序不应在处理滚动条消息时调用SetScrollRange函数来隐藏滚动条。新应用程序应使用ShowScrollBar函数隐藏滚动条。

如果调用SetScrollRange紧跟在调用SetScrollPos功能, bRedraw参数SetScrollPos必须为零,以防止滚动条被吸入两次。

标准滚动条的默认范围是0到100。滚动条控件的默认范围是空的( nMinPos和 nMaxPos参数值均为零)。由nMinPos和 nMaxPos参数指定的值之间的差不得大于MAXLONG的值。

因为指示滚动条位置的消息 WM_HSCROLL和 WM_VSCROLL限于位置数据的16位,所以对于SetScrollRange函数的 nMaxPos参数,仅依赖于这些消息来获取位置数据的应用程序的实际最大值为65,535 。但是,因为SetScrollInfo,SetScrollPos,SetScrollRange,GetScrollInfo,GetScrollPos和GetScrollRange函数支持32位滚动条位置数据,

所以有一种方法可以绕过WM_HSCROLL和 WM_VSCROLL消息的16位障碍 。有关该技术的说明,请参见GetScrollInfo。

如果nBar参数是SB_CTL并且hWnd参数指定的窗口不是系统滚动条控件,则系统将SBM_SETRANGE消息发送到该窗口以设置滚动条信息。

这使SetScrollRange可以在模仿滚动条的自定义控件上进行操作。如果窗口不处理SBM_SETRANGE消息,则SetScrollRange函数将失败。

*******************************************************************************

SetScrollPos函数:用于设置所指定滚动条中的滚动按钮的位置。

int SetScrollPos(

  HWND hWnd,//处理滚动条控件或具有标准滚动条的窗口,具体取决于nBar参数的值。

  int  nBar,//指定要设置的滚动条。

  int  nPos,//指定滚动框的新位置。该位置必须在滚动范围内。

  BOOL bRedraw//指定是否重新绘制滚动条以反映新的滚动框位置。如果此参数为TRUE,

则会重新绘制滚动条。如果为FALSE,则不会重画滚动条。

);

返回值

类型:int

如果函数成功,则返回值是滚动框的上一个位置。

如果函数失败,则返回值为零。要获取扩展的错误信息,请调用GetLastError。

*/

3-4 窗口滚动条

 

总结

       1.上述实例中,窗口滚动条是作为窗口的一种风格样式添加的。在调用CreateWindow函数创建窗口时,将窗口的风格设置为WS_OVERLAPPEDWINDOW | WS_VSCROLL,选择添加垂直滚动条。

       2.在处理WM_CREATE消息时,初始化窗口滚动条:调用SetScrollRange函数设置窗口滚动条的范围0~NUMLINS-1。并将滚动条滑块的当前位置设置为VscrollPos(初始值为0)。

       3.处理垂直滚动条消息WM_VSCROLL时使用了一个switch结构。取WM_VSCROLL消息的wParam参数低字(通知码),分别将滚动条滑块的为向上或向下滚动一行,向上或向下滚动一页。如果是鼠标拖动滚动条滑块,则WM_VSCROLL消息的wParam参数的高字记录当前滑块的位置。接下来更新滑块的位置。【注意】先判断滑块位置是否超出范围。如果位置小于0,则等于0。如果位置大于NUMLINES – 1,则等于NUMLINES – 1。然后调用GetScrollPos函数获取滑块位置,如果和之前的位置不等,则调用SetScrollPos函数重新设置滑块位置,并调用InvalidateRect函数使窗口客户区无效,调用UpdateWindow函数立即重绘窗口。

       4.虽然实例添加了窗口滚动条,可以显示所有内容,但是仍然具有3个局限:一是超出实际需要的滚动范围,存在空白区域。二是滑块大小和客户区大小不成比例。三是拖动滑块,没有实时滚动客户区。我们将在下一个实例中解决上述3个局限性。

  • 24
    点赞
  • 28
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值