日本2017最新r级:自绘滚动条

来源:百度文库 编辑:偶看新闻 时间:2024/05/08 00:36:10
我自己做的自定义滚动条,练练手。 自定义一个CCustomScroll类,从CWnd中派生 头文件(h)源码class CCustomScroll : public CWnd
{
// Construction
public:
 CCustomScroll();
 UINT       m_ThumbWidth;  //滚动块和箭头宽度
 UINT       m_ThumbHeight; //滚动块和箭头高度
 CWnd*      m_pParent;     //父窗口
 CRect      m_ClientRect;  //窗口客户区域 CRect      m_ThumbRect;   //滚动块区域 BOOL       m_ButtonDown;  //鼠标是否单击滚动块
 CPoint     m_Startpt;     //鼠标按下时的起点
 BOOL       m_IsLeft;      //滚动块是否超过左箭头
 BOOL       m_IsLeftArrow; //是否单击左滚动条按钮
 BOOL       m_IsRightArrow;//是否单击右滚动条按钮 
 BOOL       m_IsLeftRange; //是否单击了左滚动区域
 BOOL       m_IsRightRange;//是否单击了右滚动区域 UINT       m_MinRange;    //最小滚动范围
 UINT       m_MaxRange;    //最大滚动范围
 UINT       m_CurPos;      //当前的位置(逻辑单位)
 double     m_Rate;        //物理像素与逻辑单位的比率 UINT       m_LeftArrow;   //左箭头位图ID
 UINT       m_RightArrow;  //右箭头位图ID
 UINT       m_ChanelBK;    //背景位图ID
 UINT       m_ThumbBK;     //滚动块位图ID// Attributes
public:// Operations
public:// Overrides
 // ClassWizard generated virtual function overrides
 //{{AFX_VIRTUAL(CCustomScroll)
 //}}AFX_VIRTUAL// Implementation
public:
 void SetScrollRange(int minRange,int maxRange);
 void DrawHorScroll();
 void DrawControl();
 virtual ~CCustomScroll(); // Generated message map functions
protected:
 //{{AFX_MSG(CCustomScroll)
 afx_msg void OnPaint();
 afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
 afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
 afx_msg void OnMouseMove(UINT nFlags, CPoint point);
 afx_msg void OnTimer(UINT nIDEvent);
 //}}AFX_MSG DECLARE_MESSAGE_MAP()
}; 执行文件(cpp)源 为了防止画面闪烁用了双缓冲绘图技术(就是在内存设备上下文里画图,然后用StretchBlt往屏幕设备上下文上贴图防止画面闪烁图技术),具体定义可以上网去查,这里不做太多说明。我再次写了一个CMemDC 类。 class CMemDC : public CDC
{
private:
 CBitmap* m_bmp;
 CBitmap* m_oldbmp;
 CDC*  m_pDC;
 CRect  m_Rect;
public:
 CMemDC(CDC* pDC, const CRect& rect) : CDC()
 {
  CreateCompatibleDC(pDC);
  m_bmp = new CBitmap;
  m_bmp->CreateCompatibleBitmap(pDC, rect.Width(), rect.Height());
  m_oldbmp = SelectObject(m_bmp);
  m_pDC = pDC;
  m_Rect = rect;
 }
 ~CMemDC()
 {
  m_pDC->BitBlt(m_Rect.left, m_Rect.top, m_Rect.Width(), m_Rect.Height(),
    this, m_Rect.left, m_Rect.top, SRCCOPY);
  SelectObject(m_oldbmp);
  if (m_bmp != NULL)
   delete m_bmp;
 }
}; CCustomScroll::CCustomScroll()
{
 m_ButtonDown = FALSE;//鼠标是否单击滚动块
 m_IsLeft = FALSE;//滚动块是否超过左箭头
 m_MinRange = 0;
 m_MaxRange = 200;
 m_CurPos = 0;
 m_IsLeftArrow = FALSE;
 m_IsRightArrow = FALSE;
 m_IsLeftRange = FALSE;
 m_IsRightRange = FALSE;
}CCustomScroll::~CCustomScroll()
{
}
BEGIN_MESSAGE_MAP(CCustomScroll, CStatic)
 //{{AFX_MSG_MAP(CCustomScroll)
 ON_WM_PAINT()
 ON_WM_LBUTTONDOWN()
 ON_WM_LBUTTONUP()
 ON_WM_MOUSEMOVE()
 ON_WM_TIMER()
 //}}AFX_MSG_MAP
END_MESSAGE_MAP()
响应WM_PAINT消息,自制滚动条的函数就在这里了void CCustomScroll::OnPaint()
{
 CPaintDC dc(this); // device context for painting
 
 DrawControl();
 // Do not call CStatic::OnPaint() for painting messages
} void CCustomScroll::DrawControl()
{
 DrawHorScroll(); //画水平滚动条// DrawVerScroll(); 这里可以画垂直滚动条,原理一样,就不在此写了
}void CCustomScroll::DrawHorScroll()
{ //其实就是在内存设备上下文里画图,然后用StretchBlt往屏幕设备上下文上贴图
 CClientDC dc(this); CMemDC memdc(&dc,m_ClientRect);
 CDC bmpdc;
 bmpdc.CreateCompatibleDC(&dc); //当前匹配的CDC CBitmap bmp;
 bmp.LoadBitmap(m_LeftArrow);//左箭头的图片
 
 CBitmap* pOldbmp =  bmpdc.SelectObject(&bmp); // 计算左箭头的位置
 CRect LeftArrowRect (m_ClientRect.left,m_ClientRect.top,m_ClientRect.left+m_ThumbWidth,m_ClientRect.bottom);
 memdc.StretchBlt(m_ClientRect.left,m_ClientRect.top,m_ThumbWidth,m_ThumbHeight,&bmpdc,0,0,m_ThumbWidth,m_ThumbHeight,SRCCOPY); if (pOldbmp)
  bmpdc.SelectObject(pOldbmp);
 if (bmp.GetSafeHandle())
  bmp.DeleteObject(); pOldbmp = NULL;
 //通道的开始位置和宽度
 int nChanelStart = m_ClientRect.left+m_ThumbWidth;
 int nChanelWidth = m_ClientRect.Width()- 2*m_ThumbWidth;
 //绘制通道
 bmp.LoadBitmap(m_ChanelBK); pOldbmp = bmpdc.SelectObject(&bmp); memdc.StretchBlt(nChanelStart,m_ClientRect.top,nChanelWidth,m_ClientRect.Height(),&bmpdc,0,0,1,10,SRCCOPY);
 if (pOldbmp)
  bmpdc.SelectObject(pOldbmp);
 if (bmp.GetSafeHandle())
  bmp.DeleteObject(); //绘制右箭头
 bmp.LoadBitmap(m_RightArrow);
 pOldbmp =  bmpdc.SelectObject(&bmp); int nRArrowStart = m_ThumbWidth+nChanelWidth;
 memdc.StretchBlt(nRArrowStart,m_ClientRect.top,m_ThumbWidth,m_ClientRect.Height(),&bmpdc,0,0,m_ThumbWidth,m_ThumbHeight,SRCCOPY);
 //绘制滚动块
 if (bmp.GetSafeHandle())
  bmp.DeleteObject(); bmp.LoadBitmap(m_ThumbBK);
 pOldbmp =  bmpdc.SelectObject(&bmp);
 memdc.StretchBlt(m_ThumbRect.left,m_ThumbRect.top,m_ThumbRect.Width()+1,m_ThumbRect.Height(),&bmpdc,0,0,m_ThumbRect.Width(),m_ThumbRect.Height(),SRCCOPY);} 下面这个函数是处理鼠标按下事件的,如果按下的是向上或者向下按钮,并且按住不放,那么Thumb必须连续移动,但是MFC是不处理按下不放的事件的,所以这里得设置一个定制器。还有个问题就是如果鼠标拖动Thumb,在拖动过程中鼠标移出了CScrollBarEx区域,MFC也不会处理鼠标移动事件的,要用SetCapture();来捕捉消息。注意要在鼠标谈起的时候释放捕捉ReleaseCapture() void CCustomScroll::OnLButtonDown(UINT nFlags, CPoint point)
{
    m_Startpt = point;    //确定滚动区域
    CRect rcScroll = m_ClientRect;    rcScroll.left += m_ThumbWidth;
    rcScroll.right-= m_ThumbWidth;     SetCapture();    DWORD  wparam;   
    if (m_ThumbRect.PtInRect(point))//判断是否点在滑动块上
    {
        m_ButtonDown = TRUE;
    }    else if (rcScroll.PtInRect(point)) //单击滚动区域    {        CPoint centerPt = m_ThumbRect.CenterPoint();
        int offset = point.x-centerPt.x;
  
        if ((int)point.x            m_IsLeftRange = TRUE;
        if ((int)point.x>m_ThumbRect.right)//是否点击到右滚动区域
            m_IsRightRange= TRUE;         m_ThumbRect.OffsetRect(offset,0);滑动块移动        if (m_ThumbRect.left<(int)m_ThumbWidth) //判断当前滚动量是否超出了左滚动范围        {            int width = m_ThumbRect.Width();
            m_ThumbRect.left = m_ThumbWidth;
            m_ThumbRect.right = m_ThumbRect.left+width; 
            m_CurPos = m_MinRange;              wparam = MAKELONG(SB_PAGELEFT,m_CurPos) ;            ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);            DrawControl();
            return;        }        else if (m_ThumbRect.right > right>(int)(m_ClientRect.Width()-m_ThumbWidth))//是否超出了右滚动范围        {            int width = m_ThumbRect.Width();
            m_ThumbRect.left = m_ThumbWidth;
            m_ThumbRect.right = m_ThumbRect.left+width; 
            m_CurPos = m_MinRange;              wparam = MAKELONG(SB_PAGELEFT,m_CurPos) ;            ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);            DrawControl();
            return;        }        else        {             int range =  m_ThumbRect.left-m_ThumbWidth;
   
             m_CurPos = m_Rate*(range);             if (m_IsLeftRange)
             {
                wparam = MAKELONG(SB_PAGELEFT,m_CurPos) ;  
                ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd); 
             }
             else if (m_IsRightRange)
             {
               wparam = MAKELONG(SB_PAGERIGHT,m_CurPos);  
               ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
             }  
             DrawControl();             return;         }     }     else  //单击箭头按钮
     {          if (point.x<=(int)m_ThumbWidth) //单击左箭头
         {
            if (m_CurPos>m_MinRange)
                wparam = MAKELONG(SB_LINELEFT ,1);
            else
                wparam = MAKELONG(SB_LINELEFT ,0);
            ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
            if (m_CurPos>m_MinRange)
                m_CurPos-=1;
            m_IsLeftArrow = TRUE;
        }
        else //单击右箭头
        {
           if (m_CurPos>=m_MaxRange)
              wparam = MAKELONG(SB_LINERIGHT ,0);
           else
              wparam = MAKELONG(SB_LINERIGHT ,1); 
           ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
           if (m_CurPos           m_CurPos+=1;
           m_IsRightArrow = TRUE;        }
        int factpos = m_CurPos/m_Rate;  
        int width =  m_ThumbRect.Width();
        m_ThumbRect.left = m_ThumbWidth +factpos;
        m_ThumbRect.right = m_ThumbRect.left+width;        DrawControl();
        SetTimer(1,100,NULL);
   } 
   CWnd::OnLButtonDown(nFlags, point); } //定时器可以使一直按着左右键来控制滑动块变成可能void CCustomScroll::OnTimer(UINT nIDEvent)
{
    DWORD wparam;
    if (m_IsLeftArrow)
    {
        if (m_CurPos>m_MinRange)
            wparam = MAKELONG(SB_LINELEFT ,1);
        else
            wparam = MAKELONG(SB_LINELEFT ,0);
        ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd); 
        if (m_CurPos>m_MinRange)
            m_CurPos-=1;
    }
    else if (m_IsRightArrow)
    {
        if (m_CurPos< m_MaxRange)
            wparam = MAKELONG(SB_LINERIGHT,1);
        else
            wparam = MAKELONG(SB_LINERIGHT ,0);
        ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
        if (m_CurPos            m_CurPos+=1; 
    }
    int factpos = m_CurPos/m_Rate;  
    int width =  m_ThumbRect.Width();
    m_ThumbRect.left = m_ThumbWidth +factpos;
    m_ThumbRect.right = m_ThumbRect.left+width;
    DrawControl();     CWnd::OnTimer(nIDEvent);
} void CCustomScroll::OnMouseMove(UINT nFlags, CPoint point)

    if (m_ButtonDown)
    {
        int offset = point.x-m_Startpt.x;
        m_Startpt = point; 
  
        DWORD wparam;
        if (offset<=0) //向左拖动滚动块
        {
            if (m_ThumbRect.left<=(int)m_ThumbWidth)
                return; 
            else if (abs(offset)>(int)(m_ThumbRect.left-m_ThumbWidth)) //判断当前滚动量是否超出了滚动范围
            {
                int width = m_ThumbRect.Width();
                m_ThumbRect.left = m_ThumbWidth;
                m_ThumbRect.right = m_ThumbRect.left+width;
    
                m_CurPos = 0;
                wparam = MAKELONG(SB_THUMBPOSITION,m_CurPos);
                ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
                DrawControl();
                return;
            }
        }
        else if (offset>0) //向右拖动滚动块
        {
            if (m_ThumbRect.right>=m_ClientRect.Width()-m_ThumbWidth) //超出右箭头
            {
                return;
            }
            else if ( offset> m_ClientRect.Width()-m_ThumbWidth-m_ThumbRect.right) //判断是否超出了滚动范围
            {
                int width = m_ThumbRect.Width();
                m_ThumbRect.right = m_ClientRect.Width()-m_ThumbWidth; 
                m_ThumbRect.left = m_ThumbRect.right -width; 
                m_CurPos = m_MaxRange;
                wparam = MAKELONG(SB_THUMBPOSITION,m_CurPos);
                ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);
                DrawControl();
                return;
            }   
        }
          m_ThumbRect.OffsetRect(offset,0);   
        int range =  m_ThumbRect.left-m_ThumbWidth;
        m_CurPos = m_Rate*(range);        wparam = MAKELONG(SB_THUMBPOSITION,m_CurPos);
        ::SendMessage(GetParent()->m_hWnd,WM_HSCROLL,wparam,(LPARAM)m_hWnd);        DrawHorScroll();  
    }
    CWnd::OnMouseMove(nFlags, point);
}
void CCustomScroll::OnLButtonUp(UINT nFlags, CPoint point)
{
    ReleaseCapture();
    m_ButtonDown = FALSE;
    m_IsLeftRange = FALSE;
    m_IsRightRange = FALSE;    if (m_IsLeftArrow)
    {
        m_IsLeftArrow = FALSE;
        KillTimer(1);
    }
    if (m_IsRightArrow)
    {
        m_IsRightArrow = FALSE;
        KillTimer(1);
    }    CWnd::OnLButtonUp(nFlags, point);
}   
写到这里,自定义的CCustomScroll类基本写好了。我在VC2003下试了,没有问题,可以使用。