zoukankan      html  css  js  c++  java
  • VC对话框实现添加滚动条实现滚动效果

    对话框滚动条及滚动效果实现,用的api主要有: ScrollWindow, SetScrollInfo, GetScrollInfo, SetWindowOrgEx。涉及的数据结构为SCROLLINFO。

    实现的原理为:设置窗口显示的滚动条;响应滚动条的消息,在其中记录窗口原点的x和y坐标,并滚动窗口;在OnPaint中设置窗口原点,并绘图。

    SCROLLINFO

    typedef struct tagSCROLLINFO
    {
        UINT    cbSize;
        UINT    fMask;
        int     nMin;
        int     nMax;
        UINT    nPage;
        int     nPos;
        int     nTrackPos;
    }   SCROLLINFO, FAR *LPSCROLLINFO;

    cbSize: SCROLLINFO结构长度字节数,该值在设置和查询参数时都必须填写。
    fMask: 指定结构中的哪些成员是有效,该值共有如下5种选择,可以选择多种用“OR”组合起来,该值在设置和查询参数时都必须填写。

    SIF_ALL : 整个结构都有效
    SIF_DISABLENOSCROLL : 该值仅在设定参数时使用,视控件参数设定的需要来对本结构的成员进行取舍。
    SIF_PAGE : nPage成员有效
    SIF_POS : nPos成员有效
    SIF_RANGE : nMin和nMax成员有效

    nMin: 滚动范围最小值
    nMax: 滚动范围最大值
    nPage: 页尺寸,用来确定比例滚动框的大小,一般设置为窗口在宽或高,分别对应用于横向滚动条和竖向滚动条
    nPos: 滚动框的位置
    nTrackPos: 拖动时滚动框的位置,该参数只能查询,不能设置。

    API 及其参数解释

    BOOL SetWindowOrgEx(HDC hdc, int X, int Y, LPPOINT lpPoint);

    该函数用指定的坐标设置设备环境的窗口原点。
    hdc:指向设备环境的句柄。
    X:指定新窗口原点的逻辑X坐标。
    Y:指定新窗口原点的逻辑Y坐标。
    lpPoint:指向POINT结构的指针,先前的窗口原点存放在此结构中,如果lpPoint的值为NULL,则什么也没返回。
    返回值:如果函数调用成功,返回值为非零值,否则为零。

    void ScrollWindow(int xAmount, int yAmount, LPCRECT lpRect = NULL, LPCRECT lpClipRect = NULL);

    XAmount: [in]指定水平滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向左滚动窗体内容时,参数值必须为负。
    YAmount: [in]指定垂直滚动的距离,以设备单位计。如果窗口类风格为CS_OWNDC或CS_CLASSDC,则此参数则使用逻辑单位而非设备单位。当向上滚动窗体内容时,参数值必须为负。
    lpRect: [in]指向RECT结构的指针,该结构指定了将要滚动的客户区范围。若此参数为NULL,则整个客户区域将被滚动。
    lpClipRect: [in]指向RECT结构的指针,该结构指定了要滚动的裁剪区域。只有这个矩形中的位才会被滚动。在矩形之外的位不会被影响,即使它们是在lpRect矩形之内。假如lpClipRect为NULL,则不会在滚动矩形上进行裁剪。

    BOOL SetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, BOOL bRedraw = TRUE);

    fnBar:指定被设定参数的滚动条的类型。这个参数可以是下面值,含义如下:
    SB_CTL:设置滚动条控件。而参数hwnd必须是滚动条控件的句柄。
    SB_HORZ:设置所给定的窗体上标准水平滚动条参数。
    SB_VERT:设置所给定的窗体上标准垂直滚动条参数。
    lpsi:指向SCROLLINFO结构。在调用SetScrollInfo之前,设置SCROLLINFO结构中cbSize成员以标识结构大小,设置成员fMask以说明待设置的滚动条参数,并且在适当的成员中制定新的参数值。成员fMask可以为下面所列复合值,含义如下:
    SIF_DISABLENOSCROLL:如果滚动条的新参数使其为没必要,则使滚动条无效而不再移动它。
    SIF_PAGE:设置滚动页码值到由Ipsi指向的SCROLLINFO结构的nPage成员中。
    SIF_POS:设置滚动位置值到由lpsi指向的SCROLLINFO结构的nPos成员中。
    SIF_RANGE:设置滚动范围值到由lpsl指向的SCROLLINFO结构的nMin和nMax成员中。
    fRedraw:指定滚动条是否重画以反映滚动条的变化。如果这个参数为TRUE,滚动条将被重画,否则不被重画。

    BOOL GetScrollInfo(int nBar, LPSCROLLINFO lpScrollInfo, UINT nMask = SIF_ALL);
      读取滚动条的信息,数据从lpScrollInfo中返回。各参数意义同SetScrollInfo

    实例

    1.在初始化等需要添加滚动条时,使用下面的代码添加滚动条。注意:不限于初始化,程序需要时都可以重新设置

        // 给对话框添加滚动条 SB_VERT:垂直方向,SB_HORZ:水平方向
        SCROLLINFO si;                                          
        si.cbSize = sizeof(SCROLLINFO);                          
        si.fMask = SIF_PAGE | SIF_POS | SIF_RANGE;              
        si.nPos = 0;
        si.nMin = 0;  
        si.nMax = rc.Height() * 5;  
        si.nPage = rc.Height();  
        SetScrollInfo(SB_VERT, &si, FALSE);
        si.nMax = rc.Width() * 5;  
        si.nPage = rc.Width();  
        SetScrollInfo(SB_HORZ, &si, FALSE);

    2.响应WM_VSCROLL 和 WM_HSCROLL 消息,在消息响应函数中滚动窗口,并记录需要显示的窗口原点。

      ON_WM_VSCROLL()
      ON_WM_HSCROLL()

    void CPrintDlgAppDlg::OnVScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        SCROLLINFO si = {sizeof(si)};
        si.fMask = SIF_ALL;
        GetScrollInfo(SB_VERT, &si);
    
        int nPrevPos = si.nPos;
        switch(nSBCode)
        {
        case SB_TOP:
            si.nPos = si.nMin;
            break;
        case SB_BOTTOM:
            si.nPos = si.nMax;
            break;
        case SB_LINEUP:
            si.nPos -= 15;
            break;
        case SB_LINEDOWN:
            si.nPos += 15;
            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;
        default:
            break;
        }
        si.fMask = SIF_POS;
        SetScrollInfo(SB_VERT, &si, TRUE);
        if (si.nPos != nPrevPos)
        {
            m_nYPos += si.nPos - nPrevPos;
            ScrollWindow(0, nPrevPos - si.nPos, NULL, NULL);
            Invalidate(FALSE);
            UpdateWindow();
        }
    
        CDialog::OnVScroll(nSBCode, nPrevPos, pScrollBar);
    }
    
    void CPrintDlgAppDlg::OnHScroll(UINT nSBCode, UINT nPos, CScrollBar* pScrollBar)
    {
        SCROLLINFO si = {sizeof(si)};
        si.fMask = SIF_ALL;
        GetScrollInfo(SB_HORZ, &si);
    
        int nPrevPos = si.nPos;
        switch(nSBCode)
        {
        case SB_LEFT:
            si.nPos = si.nMin;
            break;
        case SB_RIGHT:
            si.nPos = si.nMax;
            break;
        case SB_LINELEFT:
            si.nPos -= 15;
            break;
        case SB_LINERIGHT:
            si.nPos += 15;
            break;
        case SB_PAGELEFT:
            si.nPos -= si.nPage;
            break;
        case SB_PAGERIGHT:
            si.nPos += si.nPage;
            break;
        case SB_THUMBTRACK:
            si.nPos = si.nTrackPos;
            break;
        default:
            break;
        }
        si.fMask = SIF_POS;
        SetScrollInfo(SB_HORZ, &si, TRUE);
        if (si.nPos != nPrevPos)
        {
            m_nXPos += si.nPos - nPrevPos;
            ScrollWindow(nPrevPos - si.nPos, 0, NULL, NULL);
            Invalidate(FALSE);
            UpdateWindow();
        }
    
        CDialog::OnHScroll(nSBCode, nPrevPos, pScrollBar);
    }

    3.在OnPaint消息中,设置窗口原点并绘图。需要注意的时,为了避免滚动时图形叠加,需要创建一块内存DC,其大小应为窗口滚动区域的大小。

    void CPrintDlgAppDlg::OnPaint()
    {
        CPaintDC dc(this); // device context for painting
    
        // 用指定的坐标设置设备环境的窗口原点
        SetWindowOrgEx(dc.m_hDC, m_nXPos, m_nYPos, NULL);
    
        // 创建一块和窗口滑动区域一样大的内存DC,这样才不会出现窗口图形叠加的问题
        CRect rc(0, 0, 0, 0);
        SCROLLINFO si = {sizeof(SCROLLINFO)};
        si.fMask = SIF_RANGE;
        GetScrollInfo(SB_VERT, &si);
        rc.bottom = si.nMax;
        GetScrollInfo(SB_HORZ, &si);
        rc.right = si.nMax;
        
    
        CDC memDC;
        memDC.CreateCompatibleDC(&dc);
        CBitmap memBitmap;
        memBitmap.CreateCompatibleBitmap(&dc, rc.Width(), rc.Height());
        CBitmap* pOldBmp = memDC.SelectObject(&memBitmap);
        memDC.FillSolidRect(&rc, RGB(0, 0, 0));
        CFont font;
        font.CreateFont(20, 0, 0, 0, FW_NORMAL, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS, CLIP_DEFAULT_PRECIS, DEFAULT_QUALITY, 
            DEFAULT_PITCH | FF_SWISS, _T("Arial")); 
        memDC.SetBkMode(TRANSPARENT);
        memDC.SetTextColor(RGB(255, 255, 255));
        CFont* pOldFont = memDC.SelectObject(&font);
        int nH = 40;
        CRect rcText(0, rc.top, rc.right, rc.top + nH);
        CString str;
        CTime time;
        for (int i = 0; i < 200; i++)
        {
            ::OffsetRect(&rcText, 0, nH);
            if (rcText.bottom > rc.bottom)
            {
                break;
            }
            time = CTime::GetCurrentTime();
            str.Format(_T("当前行:[%d] "), i);
            str += time.Format(_T("%Y年%m%d日 %H时%M分%S秒 <%c>"));
            str += _T(" -------------------- ");
            str += str;
            str += str;
            memDC.DrawText(str, rcText, DT_LEFT);
        }
    
        dc.BitBlt(0, 0, rc.Width(), rc.Height(), &memDC, 0, 0, SRCCOPY);
    
        memDC.SelectObject(pOldFont);
        memDC.SelectObject(pOldBmp);
        memDC.DeleteDC();
        memBitmap.DeleteObject();
    }


  • 相关阅读:
    【Azure Redis 缓存】Azure Redis 功能性讨论二
    【Azure Developer】如何用Microsoft Graph API管理AAD Application里面的Permissions
    【Azure 环境】通过Python SDK收集所有订阅简略信息,例如订阅id 名称, 资源组及组内资源信息等,如何给Python应用赋予相应的权限才能获取到信息呢?
    【Azure 应用服务】App Service与APIM同时集成到同一个虚拟网络后,如何通过内网访问内部VNET的APIM呢?
    【Azure 云服务】如何从Azure Cloud Service中获取项目的部署文件
    【Azure Redis 缓存】Azure Redis 异常
    【Azure 微服务】基于已经存在的虚拟网络(VNET)及子网创建新的Service Fabric并且为所有节点配置自定义DNS服务
    【Azure Redis 缓存】遇见Azure Redis不能创建成功的问题:至少一个资源部署操作失败,因为 Microsoft.Cache 资源提供程序未注册。
    【Azure Redis 缓存】如何得知Azure Redis服务有更新行为?
    【Azure API 管理】在 Azure API 管理中使用 OAuth 2.0 授权和 Azure AD 保护 Web API 后端,在请求中携带Token访问后报401的错误
  • 原文地址:https://www.cnblogs.com/diysoul/p/5759233.html
Copyright © 2011-2022 走看看