WTL 界面设计篇(CSkinPictureBox)

这个博客介绍了如何创建一个自定义的皮肤图片框控件(CSkinPictureBox),该控件支持设置不同状态(正常、高亮、按下)的背景图片,以及GIF动态图。控件实现了鼠标事件响应,包括点击、移动、离开等,还有透明效果和鼠标光标的显示控制。此外,还提供了设置提示文字和绘图模式的功能。
摘要由CSDN通过智能技术生成

头文件声明(CSkinPictureBox.h):

#pragma once

#include "SkinManager.h"
#include "../GifImage.h"

enum DRAW_MODE	// 绘图模式
{
	DRAW_MODE_STRETCH,	// 拉伸
	DRAW_MODE_CENTER	// 居中
};

class CSkinPictureBox : public CWindowImpl<CSkinPictureBox, CStatic>
{
public:
	CSkinPictureBox(void);
	~CSkinPictureBox(void);

	BEGIN_MSG_MAP_EX(CSkinPictureBox)
		MSG_WM_ERASEBKGND(OnEraseBkgnd)
		MSG_WM_PAINT(OnPaint)
		MSG_WM_LBUTTONDOWN(OnLButtonDown)
		MSG_WM_LBUTTONUP(OnLButtonUp)
		MSG_WM_MOUSEMOVE(OnMouseMove)
		MSG_WM_MOUSELEAVE(OnMouseLeave)
		MSG_WM_SETFOCUS(OnSetFocus)
		MSG_WM_KILLFOCUS(OnKillFocus)
		MSG_WM_SETCURSOR(OnSetCursor)
		MSG_WM_TIMER(OnTimer)
		MESSAGE_RANGE_HANDLER_EX(WM_MOUSEFIRST, WM_MOUSELAST, OnMouseMessage)
		MSG_WM_DESTROY(OnDestroy)
	END_MSG_MAP()

public:
	BOOL SetBgPic(LPCTSTR lpNormal, LPCTSTR lpHighlight, LPCTSTR lpDown);
	BOOL SetBitmap(LPCTSTR lpszFileName, BOOL bIsGif = FALSE);	// 设置Gif需要绝对路径
	BOOL SetBitmap(const BYTE* lpData, DWORD dwSize);
	void SetToolTipText(LPCTSTR lpszText);
	void SetDrawMode(DRAW_MODE nMode = DRAW_MODE_CENTER);
	void SetTransparent(BOOL bTransparent, HDC hBgDC);
	void SetShowCursor(BOOL bShow);

	BOOL SubclassWindow(HWND hWnd);

private:
	BOOL OnEraseBkgnd(CDCHandle dc);
	void OnPaint(CDCHandle dc);
	void OnLButtonDown(UINT nFlags, CPoint point);
	void OnLButtonUp(UINT nFlags, CPoint point);
	void OnMouseMove(UINT nFlags, CPoint point);
	void OnMouseLeave();
	void OnSetFocus(CWindow wndOld);
	void OnKillFocus(CWindow wndFocus);
	BOOL OnSetCursor(CWindow wnd, UINT nHitTest, UINT message);
	void OnTimer(UINT_PTR nIDEvent);
	LRESULT OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam);
	void OnDestroy();

	BOOL StartTrackMouseLeave();
	void DrawParentWndBg(HDC hDC);
	void CalcCenterRect(CRect& rcDest, int cx, int cy, CRect& rcCenter);

private:
	CImageEx * m_lpBgImgN, * m_lpBgImgH, * m_lpBgImgD;
	CImageEx * m_lpImage;
	CGifImage * m_lpGifImage;

	CToolTipCtrl m_ToolTipCtrl;

	HCURSOR m_hCursor;

	BOOL m_bFocus, m_bPress, m_bHover, m_bMouseTracking;

	DRAW_MODE m_nDrawMode;
	DWORD m_dwTimerId;
	BOOL m_bTransparent;
	HDC m_hBgDC;
};

源码定义(CSkinPictureBox.cpp):

#include "StdAfx.h"
#include "SkinPictureBox.h"

CSkinPictureBox::CSkinPictureBox(void)
{
	m_lpBgImgN = m_lpBgImgH = m_lpBgImgD = NULL;
	m_lpImage = NULL;
	m_lpGifImage = NULL;
	m_hCursor = NULL;
	m_bFocus = m_bPress = m_bHover = m_bMouseTracking = FALSE;
	m_nDrawMode = DRAW_MODE_CENTER;
	m_dwTimerId = NULL;
	m_bTransparent = FALSE;
	m_hBgDC = NULL;
}

CSkinPictureBox::~CSkinPictureBox(void)
{
}

BOOL CSkinPictureBox::SetBgPic(LPCTSTR lpNormal, LPCTSTR lpHighlight, LPCTSTR lpDown)
{
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgN);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgH);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgD);
	
	m_lpBgImgN = CSkinManager::GetInstance()->GetImage(lpNormal);
	m_lpBgImgH = CSkinManager::GetInstance()->GetImage(lpHighlight);
	m_lpBgImgD = CSkinManager::GetInstance()->GetImage(lpDown);

	if (NULL == m_lpBgImgN || NULL == m_lpBgImgH || NULL == m_lpBgImgD)
		return FALSE;
	else
		return TRUE;
}

BOOL CSkinPictureBox::SetBitmap(LPCTSTR lpszFileName, BOOL bIsGif/* = FALSE*/)
{
	if (m_lpGifImage != NULL)
	{
		delete m_lpGifImage;
		m_lpGifImage = NULL;
	}

	if (m_lpImage != NULL)
	{
		CSkinManager::GetInstance()->ReleaseImage(m_lpImage);
		m_lpImage = NULL;
	}

	if (m_dwTimerId != NULL)
	{
		KillTimer(m_dwTimerId);
		m_dwTimerId = NULL;
	}

	if (NULL == lpszFileName)
		return FALSE;

	if (!bIsGif)
	{
		m_lpImage = CSkinManager::GetInstance()->GetImage(lpszFileName);
		return (m_lpImage != NULL) ? TRUE : FALSE;
	}
	else
	{
		m_lpGifImage = new CGifImage;
		if (NULL == m_lpGifImage)
			return FALSE;
		BOOL bRet = m_lpGifImage->LoadFromFile(lpszFileName);
		if (!bRet)
			return FALSE;
		if (m_lpGifImage->IsAnimatedGif())
			m_dwTimerId = SetTimer(1, m_lpGifImage->GetFrameDelay(), NULL);
		return TRUE;
	}
}

BOOL CSkinPictureBox::SetBitmap(const BYTE* lpData, DWORD dwSize)
{
	if (m_lpGifImage != NULL)
	{
		delete m_lpGifImage;
		m_lpGifImage = NULL;
	}

	if (m_lpImage != NULL)
	{
		CSkinManager::GetInstance()->ReleaseImage(m_lpImage);
		m_lpImage = NULL;
	}

	if (m_dwTimerId != NULL)
	{
		KillTimer(m_dwTimerId);
		m_dwTimerId = NULL;
	}

	if (NULL == lpData || dwSize <= 0)
		return FALSE;

	m_lpGifImage = new CGifImage;
	if (NULL == m_lpGifImage)
		return FALSE;
	BOOL bRet = m_lpGifImage->LoadFromBuffer(lpData, dwSize);
	if (!bRet)
		return FALSE;
	if (m_lpGifImage->IsAnimatedGif())
		m_dwTimerId = SetTimer(1, m_lpGifImage->GetFrameDelay(), NULL);
	return TRUE;
}

void CSkinPictureBox::SetToolTipText(LPCTSTR lpszText)
{
	if (!IsWindow())		// SetToolTipText函数必须在创建按钮窗口后才能调用
		return;

	if (!m_ToolTipCtrl.IsWindow())
		m_ToolTipCtrl.Create(m_hWnd);

	if (m_ToolTipCtrl.IsWindow())
	{
		if (m_ToolTipCtrl.GetToolCount() <= 0)
		{
			CRect rcClient;
			GetClientRect(&rcClient);

			m_ToolTipCtrl.Activate(TRUE);
			m_ToolTipCtrl.AddTool(m_hWnd, lpszText, &rcClient, 1);
		}
		else
		{
			m_ToolTipCtrl.Activate(TRUE);
			m_ToolTipCtrl.UpdateTipText(lpszText, m_hWnd, 1);
		}
	}
}

void CSkinPictureBox::SetDrawMode(DRAW_MODE nMode/* = DRAW_MODE_CENTER*/)
{
	m_nDrawMode = nMode;
}

void CSkinPictureBox::SetTransparent(BOOL bTransparent, HDC hBgDC)
{
	m_bTransparent = bTransparent;
	m_hBgDC = hBgDC;
}

void CSkinPictureBox::SetShowCursor(BOOL bShow)
{
	if (bShow)
	{
		if (NULL == m_hCursor)
			m_hCursor = ::LoadCursor(NULL, IDC_HAND);
	}
	else
	{
		if (m_hCursor != NULL)
		{
			::DeleteObject(m_hCursor);
			m_hCursor = NULL;
		}
	}
}

BOOL CSkinPictureBox::SubclassWindow(HWND hWnd)
{
	BOOL bRet = __super::SubclassWindow(hWnd);
	if (bRet)
	{
		DWORD dwStyle = ::GetWindowLong(m_hWnd, GWL_STYLE);
		dwStyle |= SS_NOTIFY | SS_BITMAP;
		::SetWindowLong(m_hWnd, GWL_STYLE, dwStyle);
	}
	return bRet;
}

BOOL CSkinPictureBox::OnEraseBkgnd(CDCHandle dc)
{
	return TRUE;
}

void CSkinPictureBox::OnPaint(CDCHandle dc)
{
	CPaintDC PaintDC(m_hWnd);

	CRect rcClient;
	GetClientRect(&rcClient);

	CMemoryDC MemDC(PaintDC.m_hDC, rcClient);

	if (m_bTransparent)
		DrawParentWndBg(MemDC.m_hDC);

	int nMode = ::SetStretchBltMode(MemDC.m_hDC, HALFTONE);
	if (m_lpImage != NULL && !m_lpImage->IsNull())
	{
		if (DRAW_MODE_CENTER == m_nDrawMode)
		{
			int cx = m_lpImage->GetWidth();
			int cy = m_lpImage->GetHeight();

			CRect rcCenter;
			CalcCenterRect(rcClient, cx, cy, rcCenter);

			m_lpImage->Draw(MemDC.m_hDC, rcCenter);
		}
		else if (DRAW_MODE_STRETCH == m_nDrawMode)
		{
			m_lpImage->Draw(MemDC.m_hDC, rcClient);
		}
	}
	else if (m_lpGifImage != NULL)
	{
		if (DRAW_MODE_CENTER == m_nDrawMode)
		{
			int cx = m_lpGifImage->GetWidth();
			int cy = m_lpGifImage->GetHeight();

			CRect rcCenter;
			CalcCenterRect(rcClient, cx, cy, rcCenter);

			m_lpGifImage->Draw(MemDC.m_hDC, rcCenter);
		}
		else if (DRAW_MODE_STRETCH == m_nDrawMode)
		{
			m_lpGifImage->Draw(MemDC.m_hDC, rcClient);
		}
	}
	::SetStretchBltMode(MemDC.m_hDC, nMode);

	if (m_bPress)	// 鼠标左键按下状态
	{
		if (m_lpBgImgD != NULL && !m_lpBgImgD->IsNull())
			m_lpBgImgD->Draw(MemDC.m_hDC, rcClient);
	}
	else if (m_bHover)	// 鼠标悬停状态
	{
		if (m_lpBgImgH != NULL && !m_lpBgImgH->IsNull())
			m_lpBgImgH->Draw(MemDC.m_hDC, rcClient);
	}
	else	// 普通状态
	{
		if (m_lpBgImgN != NULL && !m_lpBgImgN->IsNull())
			m_lpBgImgN->Draw(MemDC.m_hDC, rcClient);
	}
}

void CSkinPictureBox::OnLButtonDown(UINT nFlags, CPoint point)
{
	m_bPress = TRUE;
	::InvalidateRect(m_hWnd, NULL, TRUE);
	SetMsgHandled(FALSE);
}

void CSkinPictureBox::OnLButtonUp(UINT nFlags, CPoint point)
{
	if (m_bPress)
	{
		m_bPress = FALSE;
		::InvalidateRect(m_hWnd, NULL, TRUE);
	}

	SetMsgHandled(FALSE);
}

void CSkinPictureBox::OnMouseMove(UINT nFlags, CPoint point)
{
	if (!m_bMouseTracking)
	{
		StartTrackMouseLeave();
		m_bMouseTracking = TRUE;
		m_bHover = TRUE;
		::InvalidateRect(m_hWnd, NULL, TRUE);
	}

	SetMsgHandled(FALSE);
}

void CSkinPictureBox::OnMouseLeave()
{
	m_bMouseTracking = FALSE;
	m_bHover = FALSE;
	::InvalidateRect(m_hWnd, NULL, TRUE);
	SetMsgHandled(FALSE);
}

void CSkinPictureBox::OnSetFocus(CWindow wndOld)
{
	m_bFocus = TRUE;
	::InvalidateRect(m_hWnd, NULL, TRUE);
	SetMsgHandled(FALSE);
}

void CSkinPictureBox::OnKillFocus(CWindow wndFocus)
{
	m_bFocus = FALSE;
	::InvalidateRect(m_hWnd, NULL, TRUE);
	SetMsgHandled(FALSE);
}

BOOL CSkinPictureBox::OnSetCursor(CWindow wnd, UINT nHitTest, UINT message)
{
	if (m_hCursor != NULL)
	{
		::SetCursor(m_hCursor);
		return TRUE;
	}
	SetMsgHandled(FALSE);
	return FALSE;
}

void CSkinPictureBox::OnTimer(UINT_PTR nIDEvent)
{
	if (nIDEvent == m_dwTimerId && m_lpGifImage != NULL)
	{
		KillTimer(m_dwTimerId);
		m_dwTimerId = NULL;

		m_dwTimerId = SetTimer(1, m_lpGifImage->GetFrameDelay(), NULL);

		m_lpGifImage->ActiveNextFrame();

		if (IsWindowVisible())
			Invalidate();
	}
}

LRESULT CSkinPictureBox::OnMouseMessage(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
	MSG msg = { m_hWnd, uMsg, wParam, lParam };
	if (m_ToolTipCtrl.IsWindow())
		m_ToolTipCtrl.RelayEvent(&msg);
	SetMsgHandled(FALSE);
	return 1;
}

void CSkinPictureBox::OnDestroy()
{
	if (m_dwTimerId != NULL)
	{
		KillTimer(m_dwTimerId);
		m_dwTimerId = NULL;
	}

	if (m_hCursor != NULL)
	{
		::DeleteObject(m_hCursor);
		m_hCursor = NULL;
	}

	if (m_ToolTipCtrl.IsWindow())	// ToolTipCtrl早在之前的不知道什么地方已销毁,这里显式置空m_hWnd
		m_ToolTipCtrl.DestroyWindow();
	m_ToolTipCtrl.m_hWnd = NULL;

	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgN);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgH);
	CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgD);
	CSkinManager::GetInstance()->ReleaseImage(m_lpImage);

	if (m_lpGifImage != NULL)
	{
		delete m_lpGifImage;
		m_lpGifImage = NULL;
	}
}

BOOL CSkinPictureBox::StartTrackMouseLeave()
{
	TRACKMOUSEEVENT tme = { 0 };
	tme.cbSize = sizeof(tme);
	tme.dwFlags = TME_LEAVE;
	tme.hwndTrack = m_hWnd;
	return _TrackMouseEvent(&tme);
}

void CSkinPictureBox::DrawParentWndBg(HDC hDC)
{
	HWND hParentWnd = ::GetParent(m_hWnd);

	CRect rcWindow;
	GetWindowRect(&rcWindow);
	::ScreenToClient(hParentWnd, (LPPOINT)&rcWindow); 
	::ScreenToClient(hParentWnd, ((LPPOINT)&rcWindow)+1);

	::BitBlt(hDC, 0, 0, rcWindow.Width(), rcWindow.Height(), m_hBgDC, rcWindow.left, rcWindow.top, SRCCOPY);
}

void CSkinPictureBox::CalcCenterRect(CRect& rcDest, int cx, int cy, CRect& rcCenter)
{
	int cx2 = rcDest.Width();
	int cy2 = rcDest.Height();

	int x, y;
	if (cx2 <= cx)
	{
		x = 3;
		cx = cx2-6;
	}
	else
		x = (cx2 - cx + 1) / 2;

	if (cy2 <= cy)
	{
		y = 3;
		cy = cy2-6;
	}
	else
		y = (cy2 - cy + 1) / 2;

	rcCenter = CRect(rcDest.left+x, rcDest.top+y, rcDest.left+x+cx, rcDest.top+y+cy);
}

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值