当前位置:C++技术网 > 精选软件 > win32窗口滚动条和滚动条控件使用详解

win32窗口滚动条和滚动条控件使用详解

更新时间:2016-02-22 17:21:18浏览次数:1+次

    在文章《窗口滚动条和滚动条控件的区别与联系的对比分析》中详细介绍了窗口滚动条和滚动条控件的区别和联系。不过在本文中补充一点,在使用窗口滚动条和滚动条控件时,我们使用的函数也是一样的,通过函数的参数来区分滚动条。
    我们要正常使用滚动条,需要先设置好滚动条的范围,否则滚动条的滑块无法设置位置。按照滚动条使用的函数顺序来简单介绍一下各个函数,同时对比窗口滚动条和滚动条控件使用这些函数的区别。
    在创建好滚动条控件或者添加窗口滚动条后,我们需要设置滚动条范围,然后才能正常使用。如果没有一个明确的范围,你又如何确定一个值占多少比例呢?不管系统提不提供默认值,最好自己设置一下,这是一个好的开发习惯。我现在测试的是Win10系统,并没有提供默认的滚动条范围。为了避开不同系统的差异,你就自己设置为上策!
    设置滚动条范围可以使用SetScrollRange函数。SetScrollRange第一个参数为控件句柄,如果是滚动条控件,那么就是控件句柄,如果是窗口滚动条,则是窗口滚动条所属的窗口句柄。这是区分窗口滚动条和滚动条控件的参数之一。这个参数还不能完全区分,所以就有第二个参数。SetScrollRange第二个参数有几个选择:SB_CTL(滚动条控件填这个)、SB_VERT(窗口垂直滚动条)、SB_HORZ(窗口水平滚动条)。对于滚动条控件可以通过控件句柄来区分,对于滚动条控件、窗口垂直滚动条和窗口水平滚动条的区分就是第二个参数了。这是在调用函数时需要指定不同的滚动条设置。滚动条操作相关函数都是如此。
    那么SetScrollRange函数的第三个和第四个分别指定滚动条范围最小值和最大值。范围不一定要是100个数值,从0-100,有101个数,可以很好表示音量等范围,0表示没有声音,1-100则表示音量的大小。如果你只使用100份来区分,99则表示满格音量,这就让人感觉很奇怪,为什么满格不是100呢?你要不要去解释一下呢,特别是对于很顽固的用户,你去跟他说99就是表示满格,表示最大音量,人家心理上是不接收的。这就关乎用户体验咯。
    最后一个参数是表示设置范围之后,是否需要重新绘制滚动条。如果没有更新滑块的位置,即调用SetScrollPos更新滚动条位置,就需要重绘,否则滑块更新不正常的。位置变了,滑块所在的位置也就需要变,就需要重新绘制滚动条。如果只是设置范围,就没有必要重绘滚动条了。如果是大量的修改为位置,比如循环修改10000次,就不要每次都重绘控件,而是在最后一次绘画控件,这样可以提高效率。
    设置滚动条范围的代码如下:
SetScrollRange(hScrollBar,SB_CTL,0,100,FALSE);
    然后就是设置一个滚动条初始默认的位置值,就要设置滚动条值了,默认情况下是0.设置滚动条位置的函数为SetScrollPos。第一个第二个第四个参数都和SetScrollRange一样的意义,第三个就是指定位置值,这个值不要超过滚动条范围哦,不然逻辑不对哦。不要纠结设置错了之后效果怎么样,反正都错了,哪样错一般没有什么意义。不然你也可以自己试试看。
    我们可能需要先获取滚动条的位置,然后在这个基础上修改滚动条的值。滚动条操作中,可以增减一行、可以增减一页,可以直接拖动。增减的话,就需要基于原先的值了,所以需要先获取滚动条的值。获取滚动条的位置值函数为GetScrollPos,参数只有两个,同SetScrollRange函数前两个参数。返回值就是滚动条的位置值。
    滚动条的操作中有拖拽后释放、正在拖拽、一行的增减、一页的增减,需要知道的就是,垂直和水平的在增减时方向不一样,所以按行按页增减的操作码不一样,垂直滚动条则是向上一行、向下一行、向上一页和向下一页,水平滚动条的左边对应了垂直滚动条的上边,右边对应下边。左边和上边的位置值最小,右边和下边对应的位置最大。
    所谓的一行和一页,并没有指定有多少个位置值。也就是说,向上滚动一行,你可以将位置值减1、2、3、4...,向上翻一页,你可以将位置值减1、2、3、4...,你想怎么定就怎么定。不过为了用户体验,翻页应该是比滚动行的幅度要大,大多数都是你说了算。别被“行”、“页”名词给吓住了。
    WM_HSCROLL或WM_VSCROLL的WPARAM参数的低字部分就是操作码了,而高字部分就是滚动条当前的位置。高字部分用HIWORD提取、低字部分用LOWORD提取,使用见后面的完整代码。
    最后操作完后,要设置下滚动条的位置,否则滚动条的滑块会恢复上次的位置。滚动条的位置不是自动更新的哦。所以你要使用函数SetScrollPos设置滚动条位置。函数的参数和GetScrollPos一样的。
    我们用SetWindowText来修改静态控件的文字,提示当前滑块的值。我在代码中使用了滚动条控件和窗口滚动条同时修改静态控件的文字。

    下面是程序运行截图:

窗口滚动条和滚动条控件的使用对比

【窗口滚动条和滚动条控件的使用对比】
    下面是完整的代码:
#include "windows.h"
#include <tchar.h>
TCHAR tip[]=_T("C++技术网http://www.cjjjs.com");

LRESULT CALLBACK WinProc(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
{
    static HBRUSH hBrush;
    static HWND hScrollBar,hTip;
    switch (message)
    {
        case WM_CREATE:
            {
               hScrollBar = CreateWindow(_T("scrollbar"),_T("C++技术网\r\nhttp://www.cjjjs.com"),WS_CHILD|WS_VISIBLE|SBS_VERT,50,50,20,200,hwnd,(HMENU)1,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);
               hTip = CreateWindow(_T("static"),_T("音量:50%"),WS_CHILD|WS_VISIBLE,50,250,200,20,hwnd,(HMENU)1,(HINSTANCE)GetWindowLong(hwnd,GWL_HINSTANCE),0);               
               
               SetScrollRange(hScrollBar,SB_CTL,0,100,FALSE);//必须先设定好范围,否则无法修改滚动条控件滑块位置
               SetScrollPos(hScrollBar,SB_CTL,500,FALSE);//设置初始滚动条控件位置
               SetScrollRange(hwnd,SB_VERT,0,100,FALSE);//必须先设定好范围,否则无法修改滚动条控件滑块位置
               SetScrollPos(hwnd,SB_VERT,50,FALSE);//设置初始滚动条控件位置
               return 0;
            }
        case WM_VSCROLL:
            {
                if (lParam!=NULL)
                {
                    //滚动条控件,lParam携带了滚动条控件的窗口句柄
                    if (hScrollBar==(HWND)lParam)
                    {
                        //滚动条控件被操作
                        UINT iPos = GetScrollPos(hScrollBar,SB_CTL);
                        switch(LOWORD(wParam))
                        {
                        case SB_THUMBPOSITION:
                            //拖动滚动条释放,拖动的最终位置
                            iPos = HIWORD(wParam);
                            break;
                        case SB_THUMBTRACK:
                            //正在拖动滚动条,滑块位置实时在变化
                            iPos = HIWORD(wParam);
                            break;
                        case SB_LINEUP://水平的是SB_LINELEFT
                            iPos = max(iPos-1,0);
                            break;
                        case SB_PAGEUP://水平的是SB_PAGERIGHT
                            iPos = max(iPos-10,0);
                            break;
                        case SB_LINEDOWN://水平的是SB_LINERIGHT
                            iPos = min(iPos+1,99);
                            break;
                        case SB_PAGEDOWN://水平的是SB_PAGERIGHT
                            iPos = min(iPos+10,99);
                            break;
                        }
                        SetScrollPos(hScrollBar,SB_CTL,iPos,FALSE);
                        wsprintf(tip,_T("音量:%d %%"),iPos);
                        SetWindowText(hTip,tip);
                    }
                }
                else
                {
                    //窗口滚动条
                    //窗口滚动条被操作,同滚动条控件,只是操作的窗口句柄是窗口以及参数中使用SB_VERT而不是SB_CTL
                    UINT iPos = GetScrollPos(hwnd,SB_VERT);
                    switch(LOWORD(wParam))
                    {
                    case SB_THUMBPOSITION:
                        //拖动滚动条释放,拖动的最终位置
                        iPos = HIWORD(wParam);
                        break;
                    case SB_THUMBTRACK:
                        //正在拖动滚动条,滑块位置实时在变化
                        iPos = HIWORD(wParam);
                        break;
                    case SB_LINEUP://水平的是SB_LINELEFT
                        iPos = max(iPos-1,0);
                        break;
                    case SB_PAGEUP://水平的是SB_PAGERIGHT
                        iPos = max(iPos-10,0);
                        break;
                    case SB_LINEDOWN://水平的是SB_LINERIGHT
                        iPos = min(iPos+1,99);
                        break;
                    case SB_PAGEDOWN://水平的是SB_PAGERIGHT
                        iPos = min(iPos+10,99);
                        break;
                    }
                    SetScrollPos(hwnd,SB_VERT,iPos,TRUE);
                    wsprintf(tip,_T("音量:%d %%"),iPos);
                    SetWindowText(hTip,tip);
                }
            }
            return 0;
        case WM_CTLCOLORSCROLLBAR:
            {
                hBrush = CreateSolidBrush(RGB(255,0,0));
                return (LRESULT)hBrush;
            }
        case WM_DESTROY:
            PostQuitMessage(0);
            return 0;
        default:
            break;//跳出到默认处理
    }
    return DefWindowProc(hwnd, message, wParam, lParam);
}

int WINAPI WinMain(HINSTANCE hInstance,HINSTANCE hPrev,LPSTR lpCmd,int iShow)
{
    TCHAR ClassName[] = _T("MyClass");
    TCHAR title1[] = _T("C++技术网http://www.cjjjs.com");
    WNDCLASS wndClass;
    wndClass.cbClsExtra=0;
    wndClass.cbWndExtra=0;
    wndClass.hbrBackground= (HBRUSH)GetStockObject(WHITE_BRUSH);
    wndClass.hCursor=LoadCursor(NULL,IDC_ARROW);
    wndClass.hIcon=LoadIcon(NULL,IDI_APPLICATION);
    wndClass.hInstance = hInstance;
    wndClass.lpfnWndProc = WinProc;
    wndClass.lpszClassName = ClassName;
    wndClass.lpszMenuName=NULL;
    wndClass.style=CS_HREDRAW|CS_VREDRAW|CS_DBLCLKS;

    if(!RegisterClass(&wndClass))return 0;
    HWND hwnd = CreateWindow(ClassName,title1,WS_OVERLAPPEDWINDOW|WS_VSCROLL,10,100,400,400,NULL,NULL,hInstance,NULL);
    ShowWindow(hwnd,SW_SHOWNORMAL);

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