MFC 滚动条自绘

本文介绍了一种使用MFC实现自定义绘制列表控件中垂直和水平滚动条的方法。通过创建CScrollBarEx类来覆盖默认滚动条样式,并在列表控件中进行集成。文章详细展示了如何获取滚动条信息并绘制箭头、滑块等组件。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

列表控件中的滚动条自绘

CScrollBarList .h:

#include "ScrollBarEx.h"

class CScrollBarList : public CListCtrl

{
DECLARE_DYNAMIC(CScrollBarList)
。。。。。。
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
public:
afx_msg void OnPaint();
private:
CScrollBarEx m_HScroll;
CScrollBarEx m_VScroll;

};


CScrollBarList .cpp:

#include "stdafx.h"
#include "ScrollBar.h"
#include "ScrollBarList.h"
// CScrollBarList
IMPLEMENT_DYNAMIC(CScrollBarList, CListCtrl)
。。。。。。
void CScrollBarList::PreSubclassWindow()
{
// TODO: Add your specialized code here and/or call the base class
CListCtrl::PreSubclassWindow();
m_HScroll.InitScrollBar(this, SB_HORZ);
m_VScroll.InitScrollBar(this, SB_VERT);
}


void CScrollBarList::OnPaint()
{
CListCtrl::OnPaint();
m_HScroll.UpdateScrollBar();
m_VScroll.UpdateScrollBar();
}


CScrollBarEx .h:

class CScrollBarEx : public CStatic
{

public:
BOOL InitScrollBar(CWnd *pCtrl, UINT nStyle);
void UpdateScrollBar();

protected:
afx_msg void OnPaint();
DECLARE_MESSAGE_MAP()
private:
CWnd* m_pCtrl;
UINT m_nScrollStyle;
private:
void DrawVScroll(CDC* pDC);
void DrawHScroll(CDC* pDC);
};

CScrollBarEx .cpp:

#include "stdafx.h"
#include "ScrollBarEx.h"
#include "resource.h"
#define SCROLLBAR_NORMAL_MINIMUM 45  //经验值,当Scrollbar宽度/高度小于这一数值时需要特殊处理,保证与系统的处理方式一致
BEGIN_MESSAGE_MAP(CScrollBarEx, CStatic)
ON_WM_PAINT()
END_MESSAGE_MAP()

void CScrollBarEx::OnPaint() 
{
CPaintDC dc(this); // device context for painting
// TODO: Add your message handler code here
if (m_nScrollStyle == SB_VERT) 
    {
        DrawVScroll(&dc);
    }
    else if(m_nScrollStyle == SB_HORZ)
{
DrawHScroll(&dc);
}
// Do not call CStatic::OnPaint() for painting messages
}


BOOL CScrollBarEx::InitScrollBar(CWnd *pCtrl, UINT nStyle)
{

if (pCtrl == NULL) 
    {
        return FALSE;
    }
    m_pCtrl = pCtrl;

    int nx, ny;
    if (nStyle == SB_VERT) 
    {
        nx = ::GetSystemMetrics(SM_CXVSCROLL);
        ny = ::GetSystemMetrics(SM_CYVSCROLL);
    }
    else if(nStyle == SB_HORZ)
    {
        nx = GetSystemMetrics(SM_CXHSCROLL);
        ny = GetSystemMetrics(SM_CYHSCROLL);
    }
else
{
return FALSE;
}
    m_nScrollStyle = nStyle;
CRect rect;
    pCtrl->GetWindowRect(rect);
pCtrl->ModifyStyle(0, WS_CLIPSIBLINGS);
CWnd* pParent = pCtrl->GetParent();
    pParent->ScreenToClient(rect);
   if (nStyle == SB_VERT) 
    {
        rect.left = rect.right- nx;
    }
    else if(nStyle == SB_HORZ)
    {
        rect.top = rect.bottom - ny;
    }

    BOOL bResult = Create(NULL, WS_CHILD|SS_LEFT|WS_VISIBLE|WS_EX_TOPMOST, rect, pParent);
    if (!bResult)
    {
        return FALSE;
    }
  
UpdateScrollBar();
    return TRUE;
}


void CScrollBarEx::UpdateScrollBar()
{
if(!IsWindow(m_hWnd) || m_pCtrl == NULL)
{
return;
}
m_pCtrl->SetWindowPos(&wndBottom, 0,0,0,0,SWP_NOSIZE | SWP_NOMOVE);

SCROLLINFO sf;
memset(&sf, 0, sizeof(SCROLLINFO));
sf.cbSize = sizeof(SCROLLINFO);
m_pCtrl->GetScrollInfo(m_nScrollStyle, &sf, SIF_ALL);
    if (sf.nPage < 0) 
    {
ShowWindow(SW_HIDE);
        return;
    }
SCROLLBARINFO hscr;
memset(&hscr, 0, sizeof(SCROLLBARINFO));
hscr.cbSize = sizeof(SCROLLBARINFO);
CRect rcScrollBar;


if(m_nScrollStyle == SB_VERT)
{
::GetScrollBarInfo(m_pCtrl->m_hWnd, OBJID_VSCROLL, &hscr);
rcScrollBar = CRect(hscr.rcScrollBar);
}
else if(m_nScrollStyle == SB_HORZ)
{
::GetScrollBarInfo(m_pCtrl->m_hWnd, OBJID_HSCROLL, &hscr);
rcScrollBar = CRect(hscr.rcScrollBar);
}

GetParent()->ScreenToClient(&rcScrollBar);
// TRACE("rcScrollBar.left = %d, rcScrollBar.top = %d\n", rcScrollBar.left, rcScrollBar.top);
SetWindowPos(NULL, rcScrollBar.left, rcScrollBar.top, rcScrollBar.Width(), rcScrollBar.Height(), SWP_SHOWWINDOW|SWP_NOZORDER);
Invalidate();
}


//draw vertical scrollbar
void CScrollBarEx::DrawVScroll(CDC* pDC)
{
if(m_pCtrl == NULL)
{
return;
}
int cxButton     = ::GetSystemMetrics(SM_CXVSCROLL);
    int cyButton     = ::GetSystemMetrics(SM_CYVSCROLL);
if(IsWindow(m_hWnd))
{
SCROLLBARINFO vscr;
memset(&vscr, 0, sizeof(SCROLLBARINFO));
vscr.cbSize = sizeof(SCROLLBARINFO);
if( ::GetScrollBarInfo(m_pCtrl->m_hWnd, OBJID_VSCROLL, &vscr) )

CRect rcVScrollBar(vscr.rcScrollBar);

int iWidth = vscr.dxyLineButton;
int iThumbTop = vscr.xyThumbTop;
int iThumbBottom = vscr.xyThumbBottom;

// TRACE("vscr.dxyLineButton = %d\n", iWidth);
// TRACE("vscr.xyThumbTop = %d\n", iThumbTop);
// TRACE("vscr.xyThumbBottom = %d\n", iThumbBottom);
// TRACE("rcVScrollBar: %d, %d, %d, %d \n", rcVScrollBar.left, rcVScrollBar.top, rcVScrollBar.right, rcVScrollBar.bottom);

if(rcVScrollBar.Height() < ::GetSystemMetrics(SM_CYVSCROLL)*2+1)
{
cyButton = (rcVScrollBar.Height() - 1)/2; 
}

CDC cMemDC;
cMemDC.CreateCompatibleDC(pDC);

CBitmap bmp;
BITMAP bitmap;

//The top arrow button
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_UPARROW);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0, 0, cxButton, cyButton, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

//The bottom arrow button
bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_DOWNARROW);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0, rcVScrollBar.Height() - cyButton, cxButton, cyButton, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

//The scroll bar itself
bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_SPAN);
cMemDC.SelectObject(&bmp);
bmp.GetBitmap(&bitmap);
pDC->StretchBlt(0, cyButton, rcVScrollBar.Width(), rcVScrollBar.Height() - 2*cyButton, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

if(rcVScrollBar.Height() <= SCROLLBAR_NORMAL_MINIMUM)
{
return;
}

//The thumb
bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_SLIDER_TOP);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0, iThumbTop, iWidth, bitmap.bmHeight, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);

bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_SLIDER_CENTER);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0 , iThumbTop + bitmap.bmHeight, iWidth, iThumbBottom - iThumbTop - 2*bitmap.bmHeight, 

&cMemDC, 0, 0,bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);

bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_SLIDER_BOTTOM);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0 , iThumbBottom - bitmap.bmHeight, iWidth, bitmap.bmHeight, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);


bmp.DeleteObject();
bmp.LoadBitmap(IDB_VERTICLE_SCROLLBAR_THUMB);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0, (iThumbTop + iThumbBottom)/2 - bitmap.bmHeight /2 , iWidth, bitmap.bmHeight, &cMemDC, 0, 0,

 bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

}
}
}


//draw horizontal scrollbar
void CScrollBarEx::DrawHScroll(CDC* pDC)
{
if(m_pCtrl == NULL)
{
return;
}

int cxButton     = ::GetSystemMetrics(SM_CXHSCROLL);
    int cyButton     = ::GetSystemMetrics(SM_CYHSCROLL);
if(IsWindow(m_hWnd))
{
SCROLLBARINFO hscr;
memset(&hscr, 0, sizeof(SCROLLBARINFO));
hscr.cbSize = sizeof(SCROLLBARINFO);
if( ::GetScrollBarInfo(m_pCtrl->m_hWnd, OBJID_HSCROLL, &hscr) )

CRect rcHScrollBar(hscr.rcScrollBar);

int iHeigth = hscr.dxyLineButton;
int iThumbLeft = hscr.xyThumbTop;
int iThumbRight = hscr.xyThumbBottom;


// TRACE("hscr.dxyLineButton = %d\n", iHeigth);
// TRACE("hscr.xyThumbTop = %d\n", iThumbLeft);
// TRACE("hscr.xyThumbBottom = %d\n", iThumbRight);
// TRACE("rcHScrollBar: %d, %d, %d, %d \n", rcHScrollBar.left, rcHScrollBar.top, rcHScrollBar.right, rcHScrollBar.bottom);


if(rcHScrollBar.Width() < ::GetSystemMetrics(SM_CXHSCROLL)*2+1)
{
cxButton = (rcHScrollBar.Width() - 1)/2; 
}

CDC cMemDC;
cMemDC.CreateCompatibleDC(pDC);

CBitmap bmp;
BITMAP bitmap;

//The left arrow button
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_LEFTARROW);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(0, 0, cxButton, cyButton, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

//The right arrow button
bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_RIGHTARROW);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(rcHScrollBar.Width() - cxButton, 0, cxButton, cyButton, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

//The scroll bar itself
bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_SPAN);
cMemDC.SelectObject(&bmp);
bmp.GetBitmap(&bitmap);
pDC->StretchBlt(cxButton, 0, rcHScrollBar.Width() - 2*cxButton, rcHScrollBar.Height(), &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

if(rcHScrollBar.Width() <= SCROLLBAR_NORMAL_MINIMUM)
{
return;
}

//The thumb
bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_SLIDER_LEFT);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(iThumbLeft, 0, bitmap.bmWidth, iHeigth, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);

bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_SLIDER_CENTER);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(iThumbLeft + bitmap.bmWidth , 0, iThumbRight - iThumbLeft - 2*bitmap.bmWidth,iHeigth, &cMemDC, 0, 0,

bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);


bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_SLIDER_RIGHT);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt(iThumbRight - bitmap.bmWidth , 0, bitmap.bmWidth, iHeigth, &cMemDC, 0, 0, bitmap.bmWidth, bitmap.bmHeight,SRCCOPY);


bmp.DeleteObject();
bmp.LoadBitmap(IDB_HORIZONTAL_SCROLLBAR_THUMB);
bmp.GetBitmap(&bitmap);
cMemDC.SelectObject(&bmp);
pDC->StretchBlt((iThumbLeft + iThumbRight)/2 - bitmap.bmWidth/2, 0, bitmap.bmWidth, iHeigth, &cMemDC, 0, 0, 

bitmap.bmWidth, bitmap.bmHeight, SRCCOPY);

}
}
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值