Click here to Skip to main content
15,893,381 members
Articles / Desktop Programming / MFC

Text ScrollBar Control

Rate me:
Please Sign up or sign in to vote.
5.00/5 (5 votes)
17 Jan 2012CPOL2 min read 49.9K   1.8K   14  
CScrollBarEx is a simple MFC control derived from CWnd, it can display scrollbar max, min, and current value
// ScrollBarEx.cpp : implementation file
//

#include "stdafx.h"
#include "MemDC.h"
#include "ScrollBarEx.h"
#include "intfCtrlNotifyMsg.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

#define SCROLLBAREXCLASSNAME "ScrollBarExWnd"

/////////////////////////////////////////////////////////////////////////////
// CScrollBarEx

CScrollBarEx::CScrollBarEx()
{
	RegisterWindowClass();	
	
	m_nPrecise = 2;
	m_dblMin = 0;
	m_dblMax = 100;
	m_dblCurVal = 50;
	m_crSbBk = RGB(212, 208, 200);
	m_crTextBk = RGB(126, 136, 171);
	m_crCurVal = RGB(255, 255, 255);
	m_crMaxMinVal = RGB(255, 0, 0);

	m_nLBtnStatus = BTN_NORMAL;
	m_nRBtnStatus = BTN_NORMAL;
	m_bSBPressed = FALSE;
	m_bThumbPressed = FALSE;

//	m_bTimerProc = FALSE;
	m_bSBLBtnHover = FALSE;
	m_bSBRBtnHover = FALSE;
}

CScrollBarEx::~CScrollBarEx()
{
}


BEGIN_MESSAGE_MAP(CScrollBarEx, CWnd)
	//{{AFX_MSG_MAP(CScrollBarEx)
	ON_WM_PAINT()
	ON_WM_LBUTTONDOWN()
	ON_WM_LBUTTONUP()
	ON_WM_MOUSEMOVE()
	ON_WM_TIMER()
	ON_WM_LBUTTONDBLCLK()
	ON_WM_ERASEBKGND()
	ON_WM_GETDLGCODE()
	ON_WM_KEYDOWN()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()


/////////////////////////////////////////////////////////////////////////////
// CScrollBarEx message handlers
BOOL CScrollBarEx::RegisterWindowClass(void)
{
	WNDCLASS wndcls;
	//	HINSTANCE hInst = AfxGetInstanceHandle();
	HINSTANCE hInst = AfxGetResourceHandle();
	
	if (!(::GetClassInfo(hInst, SCROLLBAREXCLASSNAME, &wndcls)))
	{
		// otherwise we need to register a new class
		wndcls.style            = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW;
		wndcls.lpfnWndProc      = ::DefWindowProc;
		wndcls.cbClsExtra       = wndcls.cbWndExtra = 0;
		wndcls.hInstance        = hInst;
		wndcls.hIcon            = NULL;
		wndcls.hCursor          = AfxGetApp()->LoadStandardCursor(IDC_ARROW);
		wndcls.hbrBackground    = NULL; // No Background brush (gives flicker)
		wndcls.lpszMenuName     = NULL;
		wndcls.lpszClassName    = SCROLLBAREXCLASSNAME;
		
		if (!AfxRegisterClass(&wndcls))
		{
			AfxThrowResourceException();
			return FALSE;
		}
	}
	
	return TRUE;
}

BOOL CScrollBarEx::Create(DWORD dwStyle, const RECT rect, CWnd *pParentWnd, UINT nID)
{
	return CWnd::Create(SCROLLBAREXCLASSNAME, "", dwStyle, rect, pParentWnd, nID);
}

void CScrollBarEx::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
	CRect rcClient;
	CRgn rgnScrollBar;
	CDC		MemDC;
	CBitmap	bm;
	CBitmap *pOldBm;	

	GetClientRect(rcClient); 
	
	rgnScrollBar.CreateRectRgnIndirect(&rcClient);
	dc.SelectClipRgn(&rgnScrollBar);

	MemDC.CreateCompatibleDC(&dc);
	bm.CreateCompatibleBitmap(&dc, rcClient.Width(), rcClient.Height());
	pOldBm = (CBitmap *)MemDC.SelectObject(&bm);

	CalcRect();
	DrawBk(&MemDC);
	DrawDataText(&MemDC);
	DrawLRButton(&MemDC);
	DrawScrollZoneButton(&MemDC);
	dc.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &MemDC, 0, 0, SRCCOPY);
	
	MemDC.SelectObject(pOldBm);
	MemDC.DeleteDC();
	// Do not call CWnd::OnPaint() for painting messages
}

void CScrollBarEx::CalcRect()
{
	CRect	rcClient, rcClientTxt, rcClientCtrl;

	GetClientRect(rcClient);

	m_rcClient = rcClientCtrl = rcClientTxt = rcClient;
	rcClientTxt.bottom = rcClientTxt.top + rcClientTxt.Height() / 2;
//	rcClientTxt.DeflateRect(1, 1);
	rcClientTxt.bottom -= 1;
	m_rcText = rcClientTxt;

	rcClientCtrl.top = rcClientCtrl.top + rcClientCtrl.Height() / 2;
//	rcClientCtrl.DeflateRect(1, 1);

	rcClientCtrl.top -= 1;
	rcClientCtrl.bottom -= 1;
	rcClientCtrl.left += 1;
	rcClientCtrl.right -= 1;

	m_rcScrollBar = m_rcSBLBtn = m_rcSBRBtn = rcClientCtrl;
	m_rcSBLBtn.right = m_rcSBLBtn.left + m_rcSBLBtn.Height();
//	m_rcSBLBtn.bottom = m_rcSBLBtn.top + 17;
	m_rcSBRBtn.left = m_rcSBRBtn.right - m_rcSBRBtn.Height();
//	m_rcSBRBtn.bottom = m_rcSBRBtn.top + 17;

	m_rcScrollBar.left = m_rcSBLBtn.right;
	m_rcScrollBar.right = m_rcSBRBtn.left;

	// ���㵱ǰֵ��λ��
	int nThumbLen = int(m_rcScrollBar.Width() * 5.0 / 100 + 0.5);
	int nThumbRangeMax = m_rcScrollBar.Width() - nThumbLen;
	// ������ֵ�ٷֱ�
	double dblPercent = (m_dblCurVal - m_dblMin) / (m_dblMax - m_dblMin);
	int nLeftPos = int(nThumbRangeMax * dblPercent);
	
	m_rcSBThumb = m_rcScrollBar;
//	m_rcSBThumb.top += 1;
	m_rcSBThumb.left = m_rcScrollBar.left + nLeftPos;
	m_rcSBThumb.right = m_rcSBThumb.left + nThumbLen;
}

void CScrollBarEx::DrawBk(CDC *pDC)
{	
	pDC->FillSolidRect(m_rcClient, m_crSbBk);
}

void CScrollBarEx::DrawDataText(CDC *pDC)
{
	// �������ֵ����Сֵ�Լ���ǰֵ
	CString strText;
	CString strFmt;

	pDC->SetBkMode(TRANSPARENT);
	pDC->FillSolidRect(m_rcText, m_crTextBk);

	// �������������Сֵ
	pDC->SetTextColor(m_crMaxMinVal);
	strFmt.Format("%%.%df", m_nPrecise);
	strText.Format(strFmt, m_dblMin);

	pDC->DrawText(strText, m_rcText, DT_VCENTER | DT_LEFT | DT_SINGLELINE);
	strText.Format(strFmt, m_dblMax);
	pDC->DrawText(strText, m_rcText, DT_VCENTER | DT_RIGHT | DT_SINGLELINE);

	// ���Ƶ�ǰֵ
	pDC->SetTextColor(m_crCurVal);
	strText.Format(strFmt, m_dblCurVal);
	pDC->DrawText(strText, m_rcText, DT_VCENTER | DT_CENTER | DT_SINGLELINE);
}

void CScrollBarEx::DrawLRButton(CDC *pDC)
{
	// draw left button	
	if (m_nLBtnStatus == BTN_NORMAL)
	{
		pDC->DrawFrameControl(m_rcSBLBtn, DFC_SCROLL, DFCS_SCROLLLEFT);
	}
	else
	{
		pDC->DrawFrameControl(m_rcSBLBtn, DFC_SCROLL, DFCS_SCROLLLEFT | DFCS_FLAT);
	}

	if (m_nRBtnStatus == BTN_NORMAL)
	{
		pDC->DrawFrameControl(m_rcSBRBtn, DFC_SCROLL, DFCS_SCROLLRIGHT);
	}
	else 
	{
		pDC->DrawFrameControl(m_rcSBRBtn, DFC_SCROLL, DFCS_SCROLLRIGHT | DFCS_FLAT);
	}

}

void CScrollBarEx::DrawScrollZoneButton(CDC *pDC)
{
	// draw fill bak color
	
	CPen NewPen;
	CPen *pOldPen;

	LOGBRUSH	LogBrush;
	
	LogBrush.lbStyle = BS_SOLID;
	LogBrush.lbColor = RGB(255, 255, 255);
	NewPen.CreatePen(PS_GEOMETRIC | PS_DOT | PS_ENDCAP_FLAT, 1, &LogBrush);

	pOldPen = pDC->SelectObject(&NewPen);
	
	int j = 0;
	for (int i = m_rcScrollBar.top; i < m_rcScrollBar.bottom; i++)
	{
		if (j % 2)
		{
			pDC->MoveTo(m_rcScrollBar.left, i);
			pDC->LineTo(m_rcScrollBar.right, i);
		}
		else
		{
			pDC->MoveTo(m_rcScrollBar.left + 1, i);
			pDC->LineTo(m_rcScrollBar.right, i);
		}

		j++;
		
	}

	pDC->SelectObject(pOldPen);	
    NewPen.DeleteObject();
	
	CRect rcThumb = m_rcSBThumb;
//	rcThumb.DeflateRect(0, 1);

	pDC->FillSolidRect(rcThumb, GetSysColor(COLOR_BTNFACE));
	pDC->DrawEdge(rcThumb, EDGE_RAISED, BF_TOPLEFT | BF_BOTTOMRIGHT);
}

void CScrollBarEx::OnLButtonDown(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	if (GetFocus()->GetSafeHwnd() != GetSafeHwnd())
	{
		SetFocus();
		TRACE("111\n");
	}
	
	double dblAdd = (m_dblMax - m_dblMin) * 0.01;
	if (dblAdd > 1)
	{
		dblAdd = 1;
	}

	SetCapture();

	BOOL bSndMsg = FALSE;

	// �ж��Ƿ��ڸ��������ڲ�
	if (m_rcSBLBtn.PtInRect(point))
	{	
	//	TRACE("m_rcSBLBtn %d\n ", GetTickCount());
		m_nLBtnStatus = BTN_FLAT;
	//	m_bLBtnPressed = TRUE;			
#if 1
			
		m_dblCurVal -= dblAdd;		
		
		if (m_dblCurVal <= m_dblMin)
		{
			m_dblCurVal = m_dblMin;
		}

	//	bSndMsg = TRUE;
#endif
		SetTimer(TIMERID_LEFTBTN, 100, NULL);	
	}
	else if (m_rcSBRBtn.PtInRect(point))
	{	
	//	SetTimer(100, 200, NULL);
		m_nRBtnStatus = BTN_FLAT;
	//	m_bRBtnPressed = TRUE;	
#if 1
		m_dblCurVal += dblAdd;		
		
		if (m_dblCurVal >= m_dblMax)
		{
			m_dblCurVal = m_dblMax;
		}

	//	bSndMsg = TRUE;
#endif
		SetTimer(TIMERID_RIGHTBTN, 100, NULL);
	}
	else if (m_rcSBThumb.PtInRect(point))
	{	
		m_bThumbPressed = TRUE;

		m_ClickPoint = point;
	}
	else if (m_rcScrollBar.PtInRect(point))
	{	
		m_bSBPressed = TRUE;
#if 1		
		// ���������ӻ��Ǽ���
		if (point.x > m_rcSBThumb.right)
		{
			m_dblCurVal += dblAdd * 2;			
		}
		else if (point.x < m_rcSBThumb.left)
		{
			m_dblCurVal -= dblAdd * 2;			
		}

		if (m_dblCurVal >= m_dblMax)
		{
			m_dblCurVal = m_dblMax;
		}
		if (m_dblCurVal <= m_dblMin)
		{
			m_dblCurVal = m_dblCurVal;
		}
		
	//	bSndMsg = TRUE;

#endif
		SetTimer(TIMERID_SCROLLBAR, 30, NULL);
	}

	Invalidate();
	
	if (bSndMsg)
	{
		SendMsgToParentWnd();
	}

//	CWnd::OnLButtonDown(nFlags, point);
}

void CScrollBarEx::OnLButtonUp(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	ReleaseCapture();	

	if (m_bThumbPressed)
	{	
		m_bThumbPressed = FALSE;		
	}
	else
	{
		Invalidate();

		KillTimer(TIMERID_SCROLLBAR);
		KillTimer(TIMERID_LEFTBTN);
		KillTimer(TIMERID_LEFTBTNHOVER);
		KillTimer(TIMERID_RIGHTBTN);
		KillTimer(TIMERID_RIGHTBTNHOVER);
		
		m_bSBPressed = FALSE;		
		
		m_bSBLBtnHover = FALSE;
		m_nLBtnStatus = BTN_NORMAL;
	//	m_bLBtnPressed = FALSE;		
		
		m_bSBRBtnHover = FALSE;
		m_nRBtnStatus = BTN_NORMAL;
	//	m_bRBtnPressed = FALSE;

		SendMsgToParentWnd();
	}

//	CWnd::OnLButtonUp(nFlags, point);
}

void CScrollBarEx::OnMouseMove(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
//	TRACE("MouseMove \n");
	if (m_bThumbPressed)
	{
		int nMoveLen = 0;

		double dblMoveVal = (point.x - m_ClickPoint.x) * 1.0 / m_rcScrollBar.Width() * (m_dblMax - m_dblMin);
		
		m_dblCurVal += dblMoveVal;
		if (m_dblCurVal >= m_dblMax)
		{
			m_dblCurVal = m_dblMax;
		}
		
		if (m_dblCurVal <= m_dblMin)
		{
			m_dblCurVal = m_dblMin;
		}
		
		SendMsgToParentWnd();
		
		m_ClickPoint = point;

		Invalidate();
	}	

//	CWnd::OnMouseMove(nFlags, point);
}

double CScrollBarEx::GetScrollBarCurVal()
{
	return m_dblCurVal;
}

void CScrollBarEx::SetScrollBarMinMaxVal(double dblMin, double dblMax)
{
	m_dblMax = dblMax;
	m_dblMin = dblMin;
}

void CScrollBarEx::SetScrollBarMinMaxValColor(COLORREF crMinMaxVal)
{
	m_crMaxMinVal = crMinMaxVal;
}

void CScrollBarEx::SetScrollBarCurVal(double dblCurVal)
{
	m_dblCurVal = dblCurVal;
}

void CScrollBarEx::SetScrollBarCurValColor(COLORREF crCurVal)
{
	m_crCurVal = crCurVal;
}

void CScrollBarEx::SetScrollBarTextBkColor(COLORREF crTextBk)
{
	m_crTextBk = crTextBk;
}

void CScrollBarEx::SetPrecise(int nPrec)
{
	m_nPrecise = nPrec;
}

void CScrollBarEx::OnTimer(UINT nIDEvent) 
{
	// TODO: Add your message handler code here and/or call default
	POINT MousePoint;
	GetCursorPos(&MousePoint);
	ScreenToClient(&MousePoint);

	BOOL	bSndMsg = FALSE;

	double dblAdd = (m_dblMax - m_dblMin) * 0.01;
	if (dblAdd > 1)
	{
		dblAdd = 1;
	}

	switch (nIDEvent)
	{
	case TIMERID_LEFTBTN:
	//	if (m_bLBtnPressed)
		{
			
			if (m_rcSBLBtn.PtInRect(MousePoint))
			{
				m_bSBLBtnHover = TRUE;
				
				KillTimer(TIMERID_LEFTBTN);
				SetTimer(TIMERID_LEFTBTNHOVER, 30, NULL);
				
				Invalidate();				
				
			}					
			
		}
		break;

	case TIMERID_LEFTBTNHOVER:
		{
			if (m_rcSBLBtn.PtInRect(MousePoint))
			{
				m_bSBLBtnHover = TRUE;
				m_nLBtnStatus = BTN_FLAT;
			//	m_bLBtnPressed = TRUE;
				m_dblCurVal -= dblAdd;
								
				if (m_dblCurVal <= m_dblMin)
				{
					m_dblCurVal = m_dblMin;
				}

				Invalidate();
			}
			else if (m_bSBLBtnHover)
			{
				m_bSBLBtnHover = FALSE;
			//	m_bLBtnPressed = FALSE;
				m_nLBtnStatus = BTN_NORMAL;
				Invalidate();
			}
		}
		break;

	case TIMERID_RIGHTBTN:
	//	if (m_bRBtnPressed)
		{
			if (m_rcSBRBtn.PtInRect(MousePoint))
			{
				m_bSBRBtnHover = TRUE;

				KillTimer(TIMERID_RIGHTBTN);
				SetTimer(TIMERID_RIGHTBTNHOVER, 30, NULL);
			
				Invalidate();			
				
			}			
		}
		break;

	case TIMERID_RIGHTBTNHOVER:
		{
			if (m_rcSBRBtn.PtInRect(MousePoint))
			{
				m_bSBRBtnHover = TRUE;
			//	m_bRBtnPressed = TRUE;
				m_nRBtnStatus = BTN_FLAT;
				
				m_dblCurVal += dblAdd;
				
				if (m_dblCurVal >= m_dblMax)
				{
					m_dblCurVal = m_dblMax;
				}
				
				bSndMsg = TRUE;
				
				Invalidate();			
				
			}
			else if (m_bSBRBtnHover)
			{
				TRACE("SBRTNHOVER OUT\n");
				m_bSBRBtnHover = FALSE;
			//	m_bRBtnPressed = FALSE;
				m_nRBtnStatus = BTN_NORMAL;
				Invalidate();
			}
		}			
		break;

	case TIMERID_SCROLLBAR:
	//	if (m_bSBPressed)
		{
			if (m_rcSBThumb.PtInRect(MousePoint))
			{
				m_bSBPressed = FALSE;
				KillTimer(100);
			}
			else if (m_rcScrollBar.PtInRect(MousePoint))
			{
				// ���������ӻ��Ǽ���
				if (MousePoint.x > m_rcSBThumb.right)
				{
					m_dblCurVal += dblAdd * 2;
										
				}
				else if (MousePoint.x < m_rcSBThumb.left)
				{
					m_dblCurVal -= dblAdd * 2;					
				}
				
				if (m_dblCurVal >= m_dblMax)
				{
					m_dblCurVal = m_dblMax;
				}
				if (m_dblCurVal <= m_dblMin)
				{
					m_dblCurVal = m_dblCurVal;
				}

				bSndMsg = TRUE;

				Invalidate();
			}		
			
		}
		break;
	}

	if (bSndMsg)
	{
		SendMsgToParentWnd();
	}

	CWnd::OnTimer(nIDEvent);
}

void CScrollBarEx::OnLButtonDblClk(UINT nFlags, CPoint point) 
{
	// TODO: Add your message handler code here and/or call default
	OnLButtonDown(nFlags, point);
//	CWnd::OnLButtonDblClk(nFlags, point);
}

void CScrollBarEx::SendMsgToParentWnd()
{
	CWnd *pWnd = GetParent();	

	::SendMessage(pWnd->m_hWnd, WM_SCROLLBAR_MSG, (WPARAM)GetDlgCtrlID(), (LPARAM)&m_dblCurVal);
}

BOOL CScrollBarEx::OnEraseBkgnd(CDC* pDC) 
{
	// TODO: Add your message handler code here and/or call default
	return TRUE;
	return CWnd::OnEraseBkgnd(pDC);
}

UINT CScrollBarEx::OnGetDlgCode() 
{
	// TODO: Add your message handler code here and/or call default
	return DLGC_WANTARROWS;
	return CWnd::OnGetDlgCode();
}

void CScrollBarEx::OnKeyDown(UINT nChar, UINT nRepCnt, UINT nFlags) 
{
	// TODO: Add your message handler code here and/or call default
	double dblAdd = (m_dblMax - m_dblMin) * 0.01;
	if (dblAdd > 1)
	{
		dblAdd = 1;
	}

	if (nChar == VK_LEFT)
	{
		m_dblCurVal -= dblAdd;
				
		if (m_dblCurVal <= m_dblMin)
		{
			m_dblCurVal = m_dblMin;
		}	
		
	}
	else if (nChar == VK_RIGHT)
	{
		m_dblCurVal += dblAdd;
		
		if (m_dblCurVal >= m_dblMax)
		{
			m_dblCurVal = m_dblMax;
		}		
	}

	SendMsgToParentWnd();
	
	Invalidate();

	CWnd::OnKeyDown(nChar, nRepCnt, nFlags);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
China China
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions