Click here to Skip to main content
15,896,207 members
Articles / Desktop Programming / MFC

Add XP Style Scrollbar to listctrl, listbox and so on (by self-draw)

Rate me:
Please Sign up or sign in to vote.
3.61/5 (13 votes)
8 Mar 2005CPOL 179.9K   1.9K   21  
Implement XP style scrollbar by self-draw
// ComboBoxXP.cpp : implementation file
//

#include "stdafx.h"
#include "sure.h"
#include "ComboBoxXP.h"

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

static WNDPROC g_pWndProc = 0;

extern "C" static LRESULT FAR PASCAL BitComboBoxListBoxProc(HWND hWnd, UINT nMsg, WPARAM wParam, LPARAM lParam)
{
	return CallWindowProc(g_pWndProc, hWnd, nMsg, wParam, lParam);
}

/////////////////////////////////////////////////////////////////////////////
// CComboBoxXP

CComboBoxXP::CComboBoxXP()
{
	m_colBackGroundHighLight = RGB(49,106,197);
	m_colTextHighLight = RGB(255,255,255);
	m_colBackGroundNormal = RGB(223,230,240);//RGB(255,255,255);
	m_colTextNormal = RGB(0,0,0);
}

CComboBoxXP::~CComboBoxXP()
{
}


BEGIN_MESSAGE_MAP(CComboBoxXP, CComboBox)
	//{{AFX_MSG_MAP(CComboBoxXP)
	ON_WM_DESTROY()
	ON_WM_PAINT()
	ON_WM_CREATE()
	ON_WM_ERASEBKGND()
	//}}AFX_MSG_MAP
	ON_MESSAGE(WM_CTLCOLORLISTBOX, OnCtlColorListBox)
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CComboBoxXP message handlers

void CComboBoxXP::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) 
{
	if( lpDrawItemStruct->itemID == -1 )
		return;

	CDC			dc;	
	dc.Attach(lpDrawItemStruct->hDC);
	
	CBrush pBrush;
	CString		sItem;

	if(lpDrawItemStruct->itemState & ODS_FOCUS)
	{
		pBrush.CreateSolidBrush(m_colBackGroundHighLight);
		dc.FillRect(&lpDrawItemStruct->rcItem, &pBrush);
		dc.SetTextColor(m_colTextHighLight);
	}
	else
	{
		pBrush.CreateSolidBrush(m_colBackGroundNormal);
		dc.FillRect(&lpDrawItemStruct->rcItem, &pBrush);
		dc.SetTextColor(m_colTextNormal);
	}

	
	if(m_lstBox.GetSafeHwnd())
	{
		// Copy the text of the item to a string
		GetLBText(lpDrawItemStruct->itemID, sItem);
		dc.SetBkMode(TRANSPARENT);

		// Draw the text after the images left postion
		lpDrawItemStruct->rcItem.left = 4;
		dc.SelectObject(m_lstBox.GetFont());
		CFont *pOldFont = dc.SelectObject(&m_font);
		dc.DrawText(sItem, &lpDrawItemStruct->rcItem, DT_VCENTER | DT_SINGLELINE);
		dc.SelectObject(pOldFont);
	}


	if(lpDrawItemStruct->itemAction & ODA_DRAWENTIRE)
		Invalidate(); 	
}

LRESULT CComboBoxXP::OnCtlColorListBox(WPARAM wParam, LPARAM lParam)
{
	//*
	// Here we need to get a reference to the listbox of the combobox
	// (the dropdown part). We can do it using 
	//TRACE("OnCtlColorListBox()\n");
	if (this->m_lstBox.m_hWnd == 0) {
		HWND hWnd = (HWND)lParam;

		if (hWnd != 0 && hWnd != m_hWnd) 
		{
			// Save the handle
			m_lstBox.m_hWnd = hWnd;

			// Subclass ListBox
			g_pWndProc = (WNDPROC)GetWindowLong(m_lstBox.m_hWnd, GWL_WNDPROC);
			SetWindowLong(m_lstBox.m_hWnd, GWL_WNDPROC, (LONG)BitComboBoxListBoxProc);
		}
	}

	//*/	
	return DefWindowProc(WM_CTLCOLORLISTBOX, wParam, lParam);
}

void CComboBoxXP::OnDestroy() 
{
	if (m_lstBox.GetSafeHwnd() != NULL)
		m_lstBox.UnsubclassWindow();

  CComboBox::OnDestroy();
}

void CComboBoxXP::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	Draw(&dc);	
	// Do not call CComboBox::OnPaint() for painting messages
}

void CComboBoxXP::Draw(CDC *pDC)
{
	CDC dc;
	dc.Attach(pDC->m_hDC);
	
	CRect rc;
	GetClientRect(&rc);
	dc.FillSolidRect(rc,GetSysColor(COLOR_WINDOW));
	BITMAP bitRight;
	{
		int nIDRight = IDB_COMBOBOXXP_DROPDOWN;
		ASSERT(nIDRight);
		CDC dcMem;
		dcMem.CreateCompatibleDC(&dc);
		CBitmap bmpComboRight;
		bmpComboRight.LoadBitmap(nIDRight);
		bmpComboRight.GetBitmap(&bitRight);
		CBitmap *pOldBmp = dcMem.SelectObject(&bmpComboRight);
		dc.BitBlt(rc.right-bitRight.bmWidth,rc.top,bitRight.bmWidth,bitRight.bmHeight,&dcMem,0,0,SRCCOPY);
		dcMem.SelectObject(pOldBmp);
	}

	CString sz;
	GetWindowText(sz);
	rc.left += 4;

	dc.SetBkMode(TRANSPARENT);
	
	RECT rcRepaint;
	GetClientRect(&rcRepaint);
	rcRepaint.left = rcRepaint.left + 2;
	rcRepaint.right = rcRepaint.right - bitRight.bmWidth-1;
	rcRepaint.top += 2; rcRepaint.bottom -= 2;
	//Set the normal/highlight color when its repainted 
	if( GetFocus() && GetFocus()->m_hWnd == m_hWnd)
	{
		dc.FillSolidRect(&rcRepaint,m_colBackGroundHighLight);
		dc.SetTextColor(m_colTextHighLight);
	}
	else
	{
		dc.FillSolidRect(&rcRepaint,m_colBackGroundNormal);
		dc.SetTextColor(m_colTextNormal);
	}
	
	{
		CRect rcClient;
		GetClientRect(rcClient);
		CRect rcText(rcClient);
		rcText.DeflateRect(6,4,bitRight.bmWidth+2,4);
		//rcText.left+=1;
		CFont *pOldFont = dc.SelectObject(&m_font);
		dc.DrawText(sz,rcText,DT_VCENTER | DT_SINGLELINE);
		dc.SelectObject(pOldFont);
	}
	
	if( m_lstBox )
	{
		 CDC *pDC = m_lstBox.GetDC();
		 m_lstBox.GetClientRect(&rc);

		 CBrush pBrush;
		 pBrush.CreateSolidBrush(m_colBackGroundNormal);
		 
 	    m_lstBox.GetDC()->FillRect(&rc,&pBrush);
	
		pDC->SetTextColor(m_colTextNormal);
		CBrush brItemData;
		RECT rcItemData;
		CString szItemString;
		brItemData.CreateSolidBrush(m_colBackGroundNormal);
		for(int i =0;i<m_lstBox.GetCount();i++)
		{
			m_lstBox.GetText(i,szItemString);
			m_lstBox.GetItemRect(i,&rcItemData);
			
			rcItemData.left += 5;

			pDC->SetBkMode(TRANSPARENT);
			pDC->SetTextColor(m_colTextNormal);

			//nListBoxTextLeft = rcItemData.left;
			
			//CFont* def_font = pDC->SelectObject(&m_Font);
			CFont *pOldFont = pDC->SelectObject(&m_font);
			pDC->DrawText(szItemString,&rcItemData, DT_VCENTER | DT_SINGLELINE);
			pDC->SelectObject(pOldFont);
		}
	}

	//draw border
	{
		CRect rcClient;
		GetClientRect(rcClient);
		CBrush br(RGB(49,106,197));
		dc.FrameRect(rcClient,&br);
	}

	dc.Detach();
}

void CComboBoxXP::PreSubclassWindow() 
{
	ModifyStyle(NULL,CBS_DROPDOWNLIST | CBS_OWNERDRAWFIXED | CBS_HASSTRINGS);
	
	if(!m_font.GetSafeHandle())
		m_font.CreatePointFont(100,"������");	
	
	CComboBox::PreSubclassWindow();
}

void CComboBoxXP::MeasureItem(LPMEASUREITEMSTRUCT lpMeasureItemStruct) 
{
			
}

int CComboBoxXP::OnCreate(LPCREATESTRUCT lpCreateStruct) 
{
	if (CComboBox::OnCreate(lpCreateStruct) == -1)
		return -1;
	
	if(!m_font.GetSafeHandle())
		m_font.CreatePointFont(100,"������");	

	return 0;
}

BOOL CComboBoxXP::OnEraseBkgnd(CDC* pDC) 
{
	return TRUE;	
	return CComboBox::OnEraseBkgnd(pDC);
}

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
xwp
Software Developer www.MayGion.com
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