WM系统滚动条设定

来源:互联网 发布:oracle数据库集群方案 编辑:程序博客网 时间:2024/05/29 17:28

WM滚动条的操作原理,要创建一个带滚动条的窗口,使用createwindow创建时带入WS_VSCROLLWS_HSCROLLod类型就能创建一个带滚动条的窗口,然后在程序中调用SetScrollInfo,配置滚动条。滚动条操作分三部:范围刷新,消息体响应,重绘界面

范围刷新:在这里填充SCROLLINFO结构,建立一系列界面与滚动条尺寸范围的对应关系

下面要填充一个scrollinfo结构,代码显示的是对纵向滚动条定位数据的填充:

    //尺寸

SCROLLINFO sbi = {sizeof(SCROLLINFO)};

 

    //客户区域

RECT rcClient;

    GetClientRect(hWnd, &rcClient);

 

    //窗口类型,需要根据窗口类型设定客户区域,因为如果纵横携有滚动条的话,需要把滚动条所占的区域从客户区域去掉,才是真正的客户显示区

DWORD dwStyle = GetWindowLong(hWnd, GWL_STYLE);

    rcClient.right -= (dwStyle | WS_HSCROLL) ? 0 : GetSystemMetrics(SM_CXVSCROLL);

rcClient.bottom -= (dwStyle | WS_VSCROLL) ? 0 : GetSystemMetrics(SM_CYHSCROLL);

 

//计算超出,就是在显示区外的尺寸。(计算超出提供给手势操作使用)

    g_nMaxXExtent = g_nBmpWidth - rcClient.right;

g_nMaxYExtent = g_nBmpHeight - rcClient.bottom;

//这是滑块的位置点,位置点和段量是有关系的,段量是10,后面就是102030

    g_nXPos = 0;

    g_nYPos = 0;

 

//info的标志位,SIF_DISABLENOSCROLL表示当界面不需要滚动时,滚动条还在界面上,设为灰化状态,如果不设这段标志,将把滚动条移掉

sbi.fMask= SIF_ALL | SIF_DISABLENOSCROLL;

//最小段位,段位表示这是一个分段,这里设的段为量是1,起始每个值都要除以段量,段量表示的是一次移动的位移。如果移动一次走一个Item的话,段量就是Item的高

sbi.nMin = 0;

//最大分段数量,总尺寸(包括显示和没显示的部分)

sbi.nMax = g_nBmpHeight - 1;

//显示区域的分段数量,与最大段位一样,但只算显示区域的分段

sbi.nPage = rcClient.bottom;

//滑块所在的段位

sbi.nPos = 0;

//滑块前一次所在的段位

    sbi.nTrackPos =0;

    SetScrollInfo(hWnd, SB_VERT, &sbi, FALSE);

 

至此一段滚动的数据信息就传入了滚动条。滚动条会依此刷新状态,这一部的操作不用我们实现,系统会自动更形滚动条。下面就要操作滚动消息体WM_VSCROLLWMHSCROLL,消息响应参数中,wParam代表对滚动条的操作,比如点向下箭头,向上箭头。响应这些动作并设定响应值.根据响应值刷新屏幕

        //根据纵横判断取出自增量(段量)

            int increment = (WM_VSCROLL==message) ? g_nVertItemSize : g_nHorizItemSize;

          //纵横判断

            int nBar = (WM_VSCROLL==message) ? SB_VERT:SB_HORZ;

          //滑块起始位置

            int * pnVal = (WM_VSCROLL==message) ? &g_nYPos:&g_nXPos;

          //起始段位,根据动作操作这个值完成滚动

            int nVal = (*pnVal)/increment;

          //最大段数量

            int nMax = 0;

            int nDelta = 0;

 

            SCROLLINFO sbi = {sizeof(SCROLLINFO)};

            sbi.fMask  = SIF_ALL;

            GetScrollInfo(hWnd, nBar, &sbi);

            int pos = sbi.nPos;

          //计算显示外的段量

            nMax = sbi.nMax - (sbi.nPage -1);  

 

            switch (LOWORD(wParam))

            {

               //到最下

                case SB_BOTTOM:

                    nVal = nMax;

                    break;

               //点向下按钮

                case SB_LINEDOWN:

                    nVal = pos + 1;

                    break;

               //点向上按钮

                case SB_LINEUP:

                    nVal = pos - 1;

                    break;

               //点在滑块下的滚动空白区

                case SB_PAGEDOWN:

                    nVal = pos + 5;

                    break;

               //点在滑块上的滚动空白区

                case SB_PAGEUP:

                    nVal = pos - 5;

                    break;

 

               //到最上

                case SB_TOP:

                    nVal = 0;

                    break;

               //在滑块上拖

                case SB_THUMBTRACK:

                    nVal = sbi.nTrackPos;

                    break;

               //直接定位

                case SB_THUMBPOSITION:

               //滚动结束

                case SB_ENDSCROLL:

                default:

                    break;

            }

          //新的滑块段位,这里有个最小和最大值保护

            nVal = max(nVal, 0);

            nVal = min(nVal, nMax);

          //差值量

            nDelta = *pnVal;

            *pnVal = nVal * increment;

            nDelta -= *pnVal;

          //如果与原位有空间就开始执行滚动

            if (nVal != pos)

            {

                RECT rcClient;

               //刷新滑块位置

                SetScrollPos(hWnd, nBar, nVal, TRUE);

 

                GetClientRect(hWnd, &rcClient);

               //判断一下纵横,区别取值

                int dx = (WM_VSCROLL==message) ? 0 : nDelta;

                int dy = (WM_VSCROLL==message) ? nDelta : 0;

               //移动窗口位置,可以不用移动窗口位置,而只通过更新界面元素调整显示

                ScrollWindowEx(hWnd, dx, dy, &rcClient, &rcClient, NULL, NULL, SW_INVALIDATE);

               //更新窗口元素

                UpdateWindow(hWnd);

         }

最终界面实现移动,同时还需要根据窗口位置重绘图形,重绘图形的操作是在OnPaint中响应实现的:

PAINTSTRUCT ps;

     HDC hdc;

     hdc = BeginPaint(hWnd, &ps);

 

     CRect rcClient;

     GetClientRect(hWnd, &rcClient);

     //FillRect(hdc,&rcClient,(HBRUSH)GetStockObject(WHITE_BRUSH));

 

     //------------------------------使用位图操作的传统方式---------------------------

     // 依据滚动位置调整贴图

     BitBlt( ps.hdc,

         ps.rcPaint.left,

         ps.rcPaint.top,

         ps.rcPaint.right - ps.rcPaint.left,

         ps.rcPaint.bottom - ps.rcPaint.top,

         g_hMemDC,

         g_nXPos + ps.rcPaint.left,

         g_nYPos + ps.rcPaint.top,

         SRCCOPY);

EndPaint(hWnd, &ps);

原创粉丝点击