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();
    }


  • 相关阅读:
    Python_代码练习_写一个判断是否为小数的函数
    Python学习杂记_11_函数(一)
    Ubuntu Server 16.04设置WiFi
    ubuntu 16.04 php 安装curl方法
    Ubuntu上搭建Git服务器
    Ubuntu 16.04 安装 Apache, MySQL, PHP7
    iOS 创建framework & bundle 主要配置
    ios 改变push方向,可以把present改为push方式
    ubuntu环境下使用apt-get配置apache+php+mysql
    [Android Studio] *.jar 与 *.aar 的生成与*.aar导入项目方法
  • 原文地址:https://www.cnblogs.com/diysoul/p/5759233.html
Copyright © 2011-2022 走看看