VC++ CSliderCtrl自绘

效果图:

头文件声明(CSWSliderCtrl.h):

#pragma once

// CSWSliderCtrl

namespace sw {
	class CSWSliderCtrl :
		public CWnd
	{
		DECLARE_DYNAMIC(CSWSliderCtrl)

	public:
		CSWSliderCtrl();
		virtual ~CSWSliderCtrl();

		void SetToolTipText(LPCSTR lpszToolTipText, BOOL bActivate = TRUE);
		void ActivateTooltip(BOOL bActivate = TRUE);
		void NoticeBkgrRefresh();
		void CommonConstruct(); // 初始化
		void InitToolTip();

	private:
		CToolTipCtrl		m_ToolTip;		// 鼠标停留提醒
		CDC					m_dcBkgr;		// 背景DC(保持了父窗体背景图像)
		BOOL				m_bTransParent;	// 背景透明
		HCURSOR				m_hCursor;		// 鼠标手势
		CBrush				m_brBkgr;		// 背景画刷
		uint64_t			m_nRangeMax;	// 最大值
		uint64_t			m_nRangeMin;	// 最小值
		uint64_t			m_nPos;			// 当前位置
		HWND				m_hParentWnd;	// 父窗口句柄
		BOOL				m_bMouseStay;	// 鼠标停留
		BOOL				m_bDraging;		// 正在拖拽
		Gdiplus::Bitmap*	m_pBitmapSlider;

	protected:
		virtual BOOL PreTranslateMessage(MSG* pMsg);

	protected:
		afx_msg BOOL OnEraseBkgnd(CDC* pDC);
		afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);
		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 OnMouseLeave();
		DECLARE_MESSAGE_MAP()

	public:
		BOOL Create(UINT nID, CWnd* pParent);

		BOOL Create(HWND hParentWnd);

		// 设置窗口背景图片
		void SetBackgroundColor(COLORREF color, BOOL bRedraw = FALSE);

		// 设置鼠标
		void SetCursor(HCURSOR hCursor = NULL);

		int GetRangeMax() const;

		// Retrieves the minimum position for the slider in the trackbar control.
		int GetRangeMin() const;

		// Retrieves the minimum and maximum positions for the slider in the trackbar control.
		void GetRange(_Out_ int& nMin, _Out_ int& nMax) const;

		// Sets the minimum position for the slider in the trackbar control.
		void SetRangeMin(_In_ int nMin, _In_ BOOL bRedraw = FALSE);

		// Sets the maximum position for the slider in the trackbar control.
		void SetRangeMax(_In_ int nMax, _In_ BOOL bRedraw = FALSE);

		// Sets the minimum and maximum positions for the slider in the trackbar control.
		void SetRange(_In_ int nMin, _In_ int nMax, _In_ BOOL bRedraw = FALSE);

		// Retrieves the current logical position of the slider in the trackbar control.
		int GetPos() const;

		// Sets the current logical position of the slider in the trackbar control.
		void SetPos(_In_ int nPos);
	};
}

源码实现(CSWSliderCtrl.cpp):

#include "pch.h"
#include "CSWSliderCtrl.h"

// CSWSliderCtrl
namespace sw {
	CSWSliderCtrl::CSWSliderCtrl()
	{
		CommonConstruct();
	}

	CSWSliderCtrl::~CSWSliderCtrl()
	{
		m_brBkgr.DeleteObject();
	}

	IMPLEMENT_DYNAMIC(CSWSliderCtrl, CWnd)
	BEGIN_MESSAGE_MAP(CSWSliderCtrl, CWnd)
		ON_WM_ERASEBKGND()
		ON_WM_SETCURSOR()
		ON_WM_PAINT()
		ON_WM_LBUTTONDOWN()
		ON_WM_LBUTTONUP()
		ON_WM_MOUSEMOVE()
		ON_WM_MOUSELEAVE()
	END_MESSAGE_MAP()

	void CSWSliderCtrl::CommonConstruct()
	{
		m_ToolTip.m_hWnd = NULL;
		m_brBkgr.CreateSolidBrush(::GetSysColor(COLOR_WINDOW));
		m_bTransParent = FALSE;
		m_hCursor = NULL;
		m_nRangeMax = 0;
		m_nRangeMin = 0;
		m_nPos = 0;
		m_hParentWnd = NULL;
		m_bMouseStay = FALSE;
		m_pBitmapSlider = sw::CSWImageFactory::getSingletonPtr()->GetSkinItemImage(_T("./skins/滑块.png"));
	}

	BOOL CSWSliderCtrl::Create(UINT nID, CWnd* pParent)
	{
		CStatic wndStatic;
		if (!wndStatic.SubclassDlgItem(nID, pParent))
			return FALSE;

		m_hParentWnd = pParent->GetSafeHwnd();
		CRect rcWindow;
		wndStatic.GetWindowRect(&rcWindow);
		pParent->ScreenToClient(&rcWindow);
		wndStatic.DestroyWindow();
		return CWnd::Create(NULL,
			NULL,
			(WS_CHILD | WS_VISIBLE),
			rcWindow,
			pParent,
			nID,
			NULL);
	}

	BOOL CSWSliderCtrl::Create(HWND hParentWnd)
	{
		if (::IsWindow(GetSafeHwnd()))
		{
			if (hParentWnd != m_hParentWnd)
				::SetParent(GetSafeHwnd(), hParentWnd);

			return TRUE; //已经创建了就不再创建了
		}

		m_hParentWnd = hParentWnd;
		static LPCTSTR lpszWndClass = NULL;
		if (lpszWndClass == NULL)
			lpszWndClass = AfxRegisterWndClass(CS_DBLCLKS,
				LoadCursor(NULL, IDC_ARROW),
				(HBRUSH)::GetStockObject(GRAY_BRUSH));
		if (lpszWndClass == NULL)
		{
			TRACE("AfxRegisterWndClass() Failed!\n");
			return FALSE;
		}

		if (!CreateEx(0,
			lpszWndClass,
			_T("CSWSliderCtrl"),
			WS_CHILD | WS_VISIBLE,
			0, 0, 0, 0,
			m_hParentWnd,
			0))
		{
			TRACE("CSWSliderCtrl::Create() Failed!\n");
			return FALSE;
		}

		if (GetSafeHwnd() == NULL)//再检查一遍,窗口没有创建成功
		{
			TRACE("CSWSliderCtrl::Create() Failed!\n");
			return FALSE;
		}

		return TRUE;
	}

	void CSWSliderCtrl::InitToolTip()
	{
		if (m_ToolTip.m_hWnd == NULL)
		{
			m_ToolTip.Create(this, TTS_ALWAYSTIP | TTS_BALLOON);
			m_ToolTip.Activate(FALSE);
		}
	}

	void CSWSliderCtrl::SetToolTipText(LPCSTR lpszToolTipText, BOOL bActivate/* = TRUE*/)
	{
		if (lpszToolTipText == NULL)
			return;

		InitToolTip();
		if (m_ToolTip.GetToolCount() == 0)
		{
			CRect rcClient;
			GetClientRect(rcClient);
			m_ToolTip.AddTool(this, (LPCTSTR)lpszToolTipText, rcClient, 1);
		}
		m_ToolTip.UpdateTipText((LPCTSTR)lpszToolTipText, this, 1);
		m_ToolTip.Activate(bActivate);
	}

	void CSWSliderCtrl::ActivateTooltip(BOOL bActivate/* = TRUE*/)
	{
		if (m_ToolTip.GetToolCount() == 0)
			return;

		m_ToolTip.Activate(bActivate);
	}

	BOOL CSWSliderCtrl::PreTranslateMessage(MSG* pMsg)
	{
		// TODO: 在此添加专用代码和/或调用基类
		InitToolTip();
		m_ToolTip.RelayEvent(pMsg);

		return CWnd::PreTranslateMessage(pMsg);
	}

	void CSWSliderCtrl::OnPaint()
	{
		if (GetSafeHwnd() == NULL)
			return;

		CPaintDC dc(this); // device context for painting
		// TODO: 在此处添加消息处理程序代码
		// 不为绘图消息调用 CWnd::OnPaint()
			// 获取窗口大小
		CRect rcClient;
		GetWindowRect(rcClient);
		rcClient.OffsetRect(-rcClient.left, -rcClient.top);

		// 使用双缓存
		sw::CMemDC dcMem(dc, this);
		// GDI+构建画布
		Gdiplus::Graphics g(dcMem);
		
		// 防止画图产生渐变
		g.SetInterpolationMode(InterpolationModeNearestNeighbor);
		g.SetPixelOffsetMode(PixelOffsetModeHalf);

		// 背景填充黑色
		if (!m_bTransParent)
		{
			LOGBRUSH logBrush;
			m_brBkgr.GetLogBrush(&logBrush);
			g.Clear(Gdiplus::Color(GetRValue(logBrush.lbColor), GetGValue(logBrush.lbColor), GetBValue(logBrush.lbColor)));
		}

		ColorMatrix colorMartrix = {
				1,0,0,0,0,
				0,1,0,0,0,
				0,0,1,0,0,
				0,0,0,float(255) / 255,0,
				0,0,0,0,1 };
		ImageAttributes imageAttr;
		imageAttr.SetColorMatrix(&colorMartrix);
		imageAttr.SetWrapMode(Gdiplus::WrapMode::WrapModeTileFlipXY);

		// 进度条背景
		Gdiplus::Bitmap* pBitmap = sw::CSWImageFactory::getSingletonPtr()->GetSkinItemImage(_T("./skins/进度条背景.png"));
		CSize sz(pBitmap->GetWidth(), pBitmap->GetHeight());
		CRect rcClip = { 0, 0, sz.cx / 3, sz.cy };

		//Rect rcImage(0, 0, pBitmap->GetWidth() / 3, pBitmap->GetHeight());
		//TextureBrush brush(pBitmap, Gdiplus::WrapMode::WrapModeTileFlipX, rcImage);
		//g.FillRectangle(&brush, RectF(0, 3, rcClient.Width(), rcClient.Height()));

		g.DrawImage(pBitmap,
			RectF(0, 3, rcClient.Width(), rcClient.Height() - 6),
			rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(),
			UnitPixel, &imageAttr, NULL, NULL);

		int nRangeMax = max(m_nRangeMax, 1);
		// 进度
		if (m_nPos > 0)
		{
			rcClip = CRect(sz.cx / 3, 0, sz.cx * 2 / 3, sz.cy);
			g.DrawImage(pBitmap,
				RectF(0, 3, rcClient.Width(), rcClient.Height() - 6),
				rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(),
				UnitPixel, &imageAttr, NULL, NULL);

			rcClip = CRect(sz.cx * 2 / 3, 0, sz.cx, sz.cy);
			g.DrawImage(pBitmap,
				RectF(0, 3, m_nPos * rcClient.Width() / nRangeMax, rcClient.Height() - 6),
				rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(),
				UnitPixel, &imageAttr, NULL, NULL);
		}

		// 滑块
		if (m_nPos >= 0)
		{
			if (m_bMouseStay)
				rcClip = CRect(m_pBitmapSlider->GetWidth() / 2, 0, m_pBitmapSlider->GetWidth(), m_pBitmapSlider->GetHeight());
			else
				rcClip = CRect(0, 0, m_pBitmapSlider->GetWidth() / 2, m_pBitmapSlider->GetHeight());
			
			g.DrawImage(m_pBitmapSlider,
				RectF(max(0, min(rcClient.Width() - rcClip.Width(), m_nPos * rcClient.Width() / nRangeMax)), 0, rcClip.Width(), rcClip.Height()),
				rcClip.left, rcClip.top, rcClip.Width(), rcClip.Height(),
				UnitPixel, &imageAttr, NULL, NULL);
		}
	}

	// CSWSliderCtrl message handlers
	void CSWSliderCtrl::NoticeBkgrRefresh()
	{
		if (m_bTransParent)
		{
			if (m_dcBkgr.m_hDC != NULL)
				m_dcBkgr.DeleteDC();

			InvalidateRect(NULL, FALSE);
		}
	}

	BOOL CSWSliderCtrl::OnEraseBkgnd(CDC* pDC)
	{
		// TODO: 在此添加消息处理程序代码和/或调用默认值
		if (m_bTransParent)
		{
			CRect rcClient;
			GetClientRect(&rcClient);
			CRect rcWindow;	GetWindowRect(rcWindow);
			GetParent()->ScreenToClient(rcWindow);
			if (m_dcBkgr.m_hDC == NULL)
			{
				// 复制父窗口背景
				CClientDC dcParentBkgr(GetParent());
				m_dcBkgr.CreateCompatibleDC(&dcParentBkgr);
				HBITMAP hBmp = ::CreateCompatibleBitmap(dcParentBkgr.GetSafeHdc(), rcClient.Width(), rcClient.Height());
				HBITMAP hOldBmp = (HBITMAP)m_dcBkgr.SelectObject(hBmp);
				m_dcBkgr.BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &dcParentBkgr, rcWindow.left, rcWindow.top, SRCCOPY);
				DeleteObject(hBmp);
			}

			pDC->BitBlt(0, 0, rcClient.Width(), rcClient.Height(), &m_dcBkgr, 0, 0, SRCCOPY);
		}

		return TRUE;// CWnd::OnEraseBkgnd(pDC);
	}

	void CSWSliderCtrl::SetBackgroundColor(COLORREF color, BOOL bRedraw)
	{
		if (m_brBkgr.GetSafeHandle() != NULL)
		{
			m_brBkgr.DeleteObject();
		}

		if (color != (COLORREF)-1)
		{
			m_brBkgr.CreateSolidBrush(color);
		}

		if (!m_bTransParent && bRedraw && GetSafeHwnd() != NULL)
		{
			Invalidate();
			UpdateWindow();
		}
	}

	void CSWSliderCtrl::SetCursor(HCURSOR hCursor)
	{
		m_hCursor = hCursor;
		if (m_hCursor == NULL)
		{
			m_hCursor = ::LoadCursor(NULL, IDC_HAND);
		}
	}

	BOOL CSWSliderCtrl::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
	{
		if (m_hCursor)
		{
			::SetCursor(m_hCursor);
			return TRUE;
		}
		else
		{
			if (m_bMouseStay)
				::SetCursor(::LoadCursor(NULL, IDC_HAND));
		}

		return FALSE;
	}

	int CSWSliderCtrl::GetRangeMax() const
	{
		return m_nRangeMax;
	}

	// Retrieves the minimum position for the slider in the trackbar control.
	int CSWSliderCtrl::GetRangeMin() const
	{
		return m_nRangeMin;
	}

	// Retrieves the minimum and maximum positions for the slider in the trackbar control.
	void CSWSliderCtrl::GetRange(_Out_ int& nMin, _Out_ int& nMax) const
	{
		nMin = m_nRangeMin;
		nMax = m_nRangeMax;
	}

	// Sets the minimum position for the slider in the trackbar control.
	void CSWSliderCtrl::SetRangeMin(_In_ int nMin, _In_ BOOL bRedraw/* = FALSE*/)
	{
		m_nRangeMin = nMin;
		if (bRedraw)
		{
			Invalidate();
			UpdateWindow();
		}
	}

	// Sets the maximum position for the slider in the trackbar control.
	void CSWSliderCtrl::SetRangeMax(_In_ int nMax, _In_ BOOL bRedraw/* = FALSE*/)
	{
		m_nRangeMax = nMax;
		if (bRedraw)
		{
			Invalidate();
			UpdateWindow();
		}
	}

	// Sets the minimum and maximum positions for the slider in the trackbar control.
	void CSWSliderCtrl::SetRange(_In_ int nMin, _In_ int nMax, _In_ BOOL bRedraw/* = FALSE*/)
	{
		m_nRangeMin = nMin;
		m_nRangeMax = nMax;
		if (bRedraw)
		{
			Invalidate();
			UpdateWindow();
		}
	}

	// Retrieves the current logical position of the slider in the trackbar control.
	int CSWSliderCtrl::GetPos() const
	{
		return m_nPos;
	}

	// Sets the current logical position of the slider in the trackbar control.
	void CSWSliderCtrl::SetPos(_In_ int nPos)
	{
		if (!m_bDraging)
		{
			m_nPos = nPos;
			Invalidate();
			UpdateWindow();
		}
	}
}

void sw::CSWSliderCtrl::OnLButtonDown(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (m_bMouseStay)
	{
		CRect rcClient;
		GetClientRect(rcClient);
		m_nPos = point.x * m_nRangeMax / rcClient.Width();
		::PostMessage(m_hParentWnd, TBM_SETPOS, GetDlgCtrlID(), m_nPos);
		InvalidateRect(NULL);
		UpdateWindow();
		m_bDraging = TRUE;
		SetCapture();
	}
	else
	{
		if ((MK_LBUTTON & nFlags) && m_nRangeMax > 0)
		{
			CRect rcClient;
			GetClientRect(rcClient);
			m_nPos = point.x * m_nRangeMax / rcClient.Width();
			::PostMessage(m_hParentWnd, TBM_SETPOS, GetDlgCtrlID(), m_nPos);
			InvalidateRect(NULL);
			UpdateWindow();
		}
	}
	CWnd::OnLButtonDown(nFlags, point);
}


void sw::CSWSliderCtrl::OnLButtonUp(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	if (m_bDraging)
	{
		m_bDraging = FALSE;
		ReleaseCapture();
	}

	m_bMouseStay = FALSE;
	CWnd::OnLButtonUp(nFlags, point);
}


void sw::CSWSliderCtrl::OnMouseMove(UINT nFlags, CPoint point)
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	int nRangeMax = max(m_nRangeMax, 1);
	CRect rcClient;
	GetClientRect(rcClient);
	CRect rcSlider = CRect(m_nPos * rcClient.Width() / nRangeMax, 0, m_pBitmapSlider->GetWidth() / 2, m_pBitmapSlider->GetHeight());
	rcSlider.right += rcSlider.left;
	rcSlider.bottom += rcSlider.top;
	point.x = max(0, point.x);

	if (PtInRect(&rcSlider, point))
	{
		if (!m_bMouseStay)
		{
			m_bMouseStay = TRUE;
			InvalidateRect(NULL);
			UpdateWindow();
		}
		else if (m_bDraging && (MK_LBUTTON & nFlags) && m_nRangeMax > 0)
		{
			m_nPos = point.x * m_nRangeMax / rcClient.Width();
			::PostMessage(m_hParentWnd, TBM_SETPOS, GetDlgCtrlID(), m_nPos);
			InvalidateRect(NULL);
			UpdateWindow();
		}
	}
	else if (m_bMouseStay && (MK_LBUTTON & nFlags) && m_nRangeMax > 0)
	{
		m_nPos = max(0, point.x * m_nRangeMax / rcClient.Width());
		::PostMessage(m_hParentWnd, TBM_SETPOS, GetDlgCtrlID(), m_nPos);
		InvalidateRect(NULL);
		UpdateWindow();
	}	

	CWnd::OnMouseMove(nFlags, point);
}


void sw::CSWSliderCtrl::OnMouseLeave()
{
	// TODO: 在此添加消息处理程序代码和/或调用默认值
	m_bMouseStay = FALSE;

	CWnd::OnMouseLeave();
}

猜你喜欢

转载自blog.csdn.net/u012156872/article/details/106196078
今日推荐