首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

关于 ScrollWindow 的很多有关问题

2013-03-16 
关于 ScrollWindow 的很多问题本帖最后由 ShuRay 于 2013-03-08 19:57:27 编辑大家好!我在看《Windows程序

关于 ScrollWindow 的很多问题
本帖最后由 ShuRay 于 2013-03-08 19:57:27 编辑     大家好!我在看《Windows程序设计》第四章关于滚动条的实现时碰到了ScrollWindow这个函数,书中介绍的不是很详细,在网上搜到的资料说的也不是很明白,有几个疑问一直没弄懂,大家帮帮忙吧~先在此谢过啦!
先贴一下代码:

case WM_VSCROLL:
        {
            // 获取滚动条当前信息
            si.cbSize = sizeof(SCROLLINFO);
            si.fMask = SIF_ALL;
            GetScrollInfo(hwnd, SB_VERT, &si);

            // 保存当前位置
            iVPos = si.nPos;

            switch(LOWORD(wParam))
            {
            case SB_TOP:
                si.nPos = si.nMin;
                break;
            case SB_BOTTOM:
                si.nPos = si.nMax;
                break;
            case SB_LINEUP:
                si.nPos -= 1;
                break;
            case SB_LINEDOWN:
                si.nPos += 1;
                break;
            case SB_PAGEUP:
                si.nPos -= si.nPage;
                break;
            case SB_PAGEDOWN:
                si.nPos += si.nPage;
                break;
            case SB_THUMBTRACK:
                si.nPos = si.nTrackPos;
                break;
            case SB_ENDSCROLL:
                break;
            case SB_THUMBPOSITION:
                break;
            default:
                break;


            }

            //SetScrollInfo时如果pos不在range内,windows会自动调整,
            //但要再次GetScrollInfo才能得到调整过后的正确位置pos
            si.fMask = SIF_POS;
            SetScrollInfo(hwnd, SB_VERT, &si, TRUE);
            GetScrollInfo(hwnd, SB_VERT, &si);

            if (iVPos != si.nPos)   //只有当滚动条位置改变时才执行以下操作
            {
                ScrollWindow(hwnd, 0, cyChar*(iVPos-si.nPos), NULL, NULL);  //更新客户区
                UpdateWindow(hwnd); //立即刷新,发送一个不进队的WM_PAINT消息
            }
        }
        return 0;

    case WM_PAINT:
        {
            // 获取滚动条信息
            si.cbSize = sizeof(SCROLLINFO);
            si.fMask = SIF_ALL;
            GetScrollInfo(hwnd, SB_VERT, &si);
            iVPos = si.nPos;

            hdc = BeginPaint(hwnd, &ps);
            iPaintBgn = max(si.nMin, iVPos + ps.rcPaint.top/cyChar);
            iPaintEnd = min(si.nMax, iVPos + ps.rcPaint.bottom/cyChar);
            for (int i = iPaintBgn; i <= iPaintEnd; i++)
            {
                int x, y;
                y = cyChar*(i-iVPos);
                TextOut(hdc, 0, y, sysmetrics[i].szLabel, lstrlen(sysmetrics[i].szLabel));
                TextOut(hdc, 22*cxCaps, y, sysmetrics[i].szDesc, lstrlen(sysmetrics[i].szDesc));

                SetTextAlign(hdc, TA_RIGHT | TA_TOP);
                TCHAR szBuffer[10];
                int iLength;
                iLength = wsprintf(szBuffer, TEXT("%5d"), GetSystemMetrics(sysmetrics[i].iIndex));


                TextOut(hdc, 22*cxCaps+40*cxChar, y, szBuffer, iLength);
                SetTextAlign(hdc, TA_LEFT | TA_TOP);
            }
            EndPaint(hwnd, &ps);
        }
        return 0;


    问题如下:
    1. 我大约知道ScrollWindow(程序第50行)是滚动窗口的,但是它到底是怎样的一个实现原理呢?什么是“未被scrollWindow覆盖的区域”?
    2. UpdateWindow(程序第51行)在这里似乎没有什么作用,网上查的说“只绘制未被滚动操作覆盖的一行,加快绘制速度”,没明白什么意思?
    3. 在WM_PAINT下面,其实还是计算出了显示在客户区的行数的范围,只绘制了这个范围内的数据。把ScrollWindow(hwnd, 0, cyChar*(iVPos-si.nPos), NULL, NULL);替换成InvalidateRect(hwnd, NULL, TRUE);也能实现同样的效果,唯一不同的是使用InvalidateRect时屏幕会闪烁。感觉ScrollWindow在这里体现不出比InvalidateRect有更大的优越性? C++ Windows编程 滚动条 ScrollWindow
[解决办法]
ScrollWindow的操作是根据参数的滚动范围 算出 不会滚出显示区域的矩形,对这部分像素直接BitBlt到新的合适位置,对于滚动出现的新的矩形,擦除背景,设该矩形为无效区域

源代码中的紧随的UpdateWindow没有太大意义,窗口有无效区域会触发WM_PAINT,新的区域也会很及时的刷新

替换成InvalidateRect(hwnd, NULL, TRUE);效果是一样的,但由于刚擦除了整个背景紧接着又画图,两个显示的反差太大,在人看来就是一种闪烁
使用ScrollWindow,大部分的区域是一次性BitBlt更新的,没有擦除背景这个显示的中间状态,只有新出现的矩形经过 擦除 和 重绘的过程,所以闪烁现象不明显得多

热点排行