头文件声明(CSkinComboBox.h):
#pragma once
#include "SkinManager.h"
#define WM_CBO_EDIT_MOUSE_HOVER WM_USER + 1
#define WM_CBO_EDIT_MOUSE_LEAVE WM_USER + 2
#define WM_CBO_LIST_HIDE WM_USER + 3
class CSkinComboBoxEdit : public CWindowImpl<CSkinComboBoxEdit, CEdit>
{
public:
CSkinComboBoxEdit(void);
~CSkinComboBoxEdit(void);
BEGIN_MSG_MAP_EX(CSkinComboBoxEdit)
MSG_WM_ERASEBKGND(OnEraseBkgnd)
MSG_WM_MOUSEMOVE(OnMouseMove)
MSG_WM_MOUSELEAVE(OnMouseLeave)
MSG_WM_SETFOCUS(OnSetFocus)
MSG_WM_KILLFOCUS(OnKillFocus)
MSG_OCM_CTLCOLOREDIT(OnCtlColor)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
public:
void SetOwnerWnd(HWND hWnd);
void SetDefaultText(LPCTSTR lpszText);
BOOL IsDefaultText();
void SetDefaultTextMode(BOOL bIsDefText);
BOOL SubclassWindow(HWND hWnd);
private:
BOOL OnEraseBkgnd(CDCHandle dc);
void OnMouseMove(UINT nFlags, CPoint point);
void OnMouseLeave();
void OnSetFocus(CWindow wndOld);
void OnKillFocus(CWindow wndFocus);
HBRUSH OnCtlColor(CDCHandle dc, CEdit edit);
BOOL StartTrackMouseLeave();
void SetMarginsEx(int nLeft, int nTop, int nRight, int nBottom); // 设置上下左右边距函数
private:
HWND m_hOwnerWnd;
BOOL m_bMouseTracking;
BOOL m_bIsDefText;
CString m_strDefText;
HBRUSH m_hBrush;
};
class CSkinComboBoxListBox : public CWindowImpl<CSkinComboBoxListBox, CListBox>
{
public:
CSkinComboBoxListBox(void);
~CSkinComboBoxListBox(void);
BEGIN_MSG_MAP_EX(CSkinComboBoxListBox)
MSG_WM_SHOWWINDOW(OnShowWindow)
END_MSG_MAP()
public:
void SetOwnerWnd(HWND hWnd);
private:
void OnShowWindow(BOOL bShow, UINT nStatus);
private:
HWND m_hOwnerWnd;
};
class CSkinComboBox : public CWindowImpl<CSkinComboBox, CComboBox>
{
public:
CSkinComboBox(void);
~CSkinComboBox(void);
BEGIN_MSG_MAP_EX(CSkinComboBox)
MSG_WM_CREATE(OnCreate)
MSG_WM_ERASEBKGND(OnEraseBkgnd)
MSG_WM_SIZE(OnSize)
MSG_WM_PAINT(OnPaint)
MSG_WM_LBUTTONDOWN(OnLButtonDown)
MSG_WM_LBUTTONUP(OnLButtonUp)
MSG_WM_MOUSEMOVE(OnMouseMove)
MSG_WM_MOUSELEAVE(OnMouseLeave)
MSG_WM_DESTROY(OnDestroy)
MESSAGE_HANDLER_EX(WM_CBO_EDIT_MOUSE_HOVER, OnEditMouseHover)
MESSAGE_HANDLER_EX(WM_CBO_EDIT_MOUSE_LEAVE, OnEditMouseLeave)
MESSAGE_HANDLER_EX(WM_CBO_LIST_HIDE, OnListHide)
DEFAULT_REFLECTION_HANDLER()
END_MSG_MAP()
public:
BOOL SetBgNormalPic(LPCTSTR lpszFileName, RECT * lpNinePart = NULL);
BOOL SetBgHotPic(LPCTSTR lpszFileName, RECT * lpNinePart = NULL);
BOOL SetArrowNormalPic(LPCTSTR lpszFileName);
BOOL SetArrowHotPic(LPCTSTR lpszFileName);
BOOL SetArrowPushedPic(LPCTSTR lpszFileName);
void SetTransparent(BOOL bTransparent, HDC hBgDC);
void SetDefaultText(LPCTSTR lpszText);
BOOL IsDefaultText();
void SetMarginsEx(int nLeft, int nTop, int nRight, int nBottom); // 设置上下左右边距函数
void SetArrowWidth(int nWidth);
BOOL SubclassWindow(HWND hWnd);
private:
int OnCreate(LPCREATESTRUCT lpCreateStruct);
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 OnSize(UINT nType, CSize size);
void OnDestroy();
LRESULT OnEditMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnEditMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam);
LRESULT OnListHide(UINT uMsg, WPARAM wParam, LPARAM lParam);
BOOL StartTrackMouseLeave();
void CalcCenterRect(CRect& rcDest, int cx, int cy, CRect& rcCenter);
void DrawParentWndBg(HDC hDC);
private:
CImageEx * m_lpBgImgN;
CImageEx * m_lpBgImgH;
CImageEx * m_lpArrowImgN;
CImageEx * m_lpArrowImgH;
CImageEx * m_lpArrowImgP;
BOOL m_bFocus, m_bPress, m_bHover, m_bMouseTracking;
BOOL m_bArrowPress, m_bArrowHover;
BOOL m_bTransparent;
HDC m_hBgDC;
int m_nArrowWidth;
CRect m_rcArrow;
CSkinComboBoxEdit m_Edit;
CSkinComboBoxListBox m_ListBox;
};
源码定义(CSkinComboBox.cpp):
#include "StdAfx.h"
#include "SkinComboBox.h"
CSkinComboBoxEdit::CSkinComboBoxEdit(void)
{
m_hOwnerWnd = NULL;
m_bMouseTracking = FALSE;
m_bIsDefText = FALSE;
m_hBrush = NULL;
}
CSkinComboBoxEdit::~CSkinComboBoxEdit(void)
{
if (m_hBrush != NULL)
{
::DeleteObject(m_hBrush);
m_hBrush = NULL;
}
}
void CSkinComboBoxEdit::SetOwnerWnd(HWND hWnd)
{
m_hOwnerWnd = hWnd;
}
void CSkinComboBoxEdit::SetDefaultText(LPCTSTR lpszText)
{
m_strDefText = lpszText;
}
BOOL CSkinComboBoxEdit::IsDefaultText()
{
return m_bIsDefText;
}
void CSkinComboBoxEdit::SetDefaultTextMode(BOOL bIsDefText)
{
if (bIsDefText == m_bIsDefText)
return;
m_bIsDefText = bIsDefText;
if (m_bIsDefText)
{
SetWindowText(m_strDefText);
}
else
{
SetWindowText(_T(""));
}
}
BOOL CSkinComboBoxEdit::SubclassWindow(HWND hWnd)
{
__super::SubclassWindow(hWnd);
SetDefaultText(m_strDefText);
// CRect rcClient;
// GetClientRect(&rcClient);
// rcClient.left += 200;
// this->SetRect(rcClient);
// SetMarginsEx(30, 0, 0, 0);
return TRUE;
}
BOOL CSkinComboBoxEdit::OnEraseBkgnd(CDCHandle dc)
{
return TRUE;
}
void CSkinComboBoxEdit::OnMouseMove(UINT nFlags, CPoint point)
{
SetMsgHandled(FALSE);
if (!m_bMouseTracking)
{
m_bMouseTracking = TRUE;
StartTrackMouseLeave();
if (::IsWindow(m_hOwnerWnd))
::SendMessage(m_hOwnerWnd, WM_CBO_EDIT_MOUSE_HOVER, 0, 0);
}
}
void CSkinComboBoxEdit::OnMouseLeave()
{
SetMsgHandled(FALSE);
m_bMouseTracking = FALSE;
if (::IsWindow(m_hOwnerWnd))
::SendMessage(m_hOwnerWnd, WM_CBO_EDIT_MOUSE_LEAVE, 0, 0);
}
void CSkinComboBoxEdit::OnSetFocus(CWindow wndOld)
{
SetMsgHandled(FALSE);
if (m_bIsDefText)
{
m_bIsDefText = FALSE;
SetWindowText(_T(""));
}
}
void CSkinComboBoxEdit::OnKillFocus(CWindow wndFocus)
{
SetMsgHandled(FALSE);
if (GetWindowTextLength() <= 0 && !m_strDefText.IsEmpty())
{
m_bIsDefText = TRUE;
SetWindowText(m_strDefText);
}
}
HBRUSH CSkinComboBoxEdit::OnCtlColor(CDCHandle dc, CEdit edit)
{
CRect rcWindow;
GetWindowRect(&rcWindow);
CRect rcClient;
GetClientRect(&rcClient);
ClientToScreen(&rcClient);
rcClient.OffsetRect(-rcWindow.left, -rcWindow.top);
rcWindow.OffsetRect(-rcWindow.left, -rcWindow.top);
if (NULL == m_hBrush)
m_hBrush = ::CreateSolidBrush(RGB(255,255,255));
if (m_bIsDefText)
::SetTextColor(dc, RGB(128,128,128));
else
::SetTextColor(dc, RGB(0,0,0));
return (HBRUSH)m_hBrush;
}
BOOL CSkinComboBoxEdit::StartTrackMouseLeave()
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = m_hWnd;
return _TrackMouseEvent(&tme);
}
// 设置上下左右边距函数
void CSkinComboBoxEdit::SetMarginsEx(int nLeft, int nTop, int nRight, int nBottom)
{
CRect rtClient;
GetClientRect(rtClient);
CRect rt(rtClient.left + nLeft, rtClient.top + nTop,
rtClient.right - nRight, rtClient.bottom - nBottom);
SetRectNP(rt);
}
CSkinComboBoxListBox::CSkinComboBoxListBox(void)
{
m_hOwnerWnd = NULL;
}
CSkinComboBoxListBox::~CSkinComboBoxListBox(void)
{
}
void CSkinComboBoxListBox::SetOwnerWnd(HWND hWnd)
{
m_hOwnerWnd = hWnd;
}
void CSkinComboBoxListBox::OnShowWindow(BOOL bShow, UINT nStatus)
{
SetMsgHandled(FALSE);
if (!bShow)
{
::SendMessage(m_hOwnerWnd, WM_CBO_LIST_HIDE, 0, 0);
}
}
CSkinComboBox::CSkinComboBox(void)
{
m_lpBgImgN = NULL;
m_lpBgImgH = NULL;
m_lpArrowImgN = NULL;
m_lpArrowImgH = NULL;
m_lpArrowImgP = NULL;
m_bFocus = m_bPress = m_bHover = m_bMouseTracking = FALSE;
m_bTransparent = FALSE;
m_hBgDC = NULL;
m_bArrowPress = FALSE;
m_bArrowHover = FALSE;
m_nArrowWidth = 17;
m_rcArrow.SetRectEmpty();
}
CSkinComboBox::~CSkinComboBox(void)
{
}
BOOL CSkinComboBox::SetBgNormalPic(LPCTSTR lpszFileName, RECT * lpNinePart/* = NULL*/)
{
CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgN);
m_lpBgImgN = CSkinManager::GetInstance()->GetImage(lpszFileName);
if (m_lpBgImgN != NULL)
m_lpBgImgN->SetNinePart(lpNinePart);
return (m_lpBgImgN != NULL) ? TRUE : FALSE;
}
BOOL CSkinComboBox::SetBgHotPic(LPCTSTR lpszFileName, RECT * lpNinePart/* = NULL*/)
{
CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgH);
m_lpBgImgH = CSkinManager::GetInstance()->GetImage(lpszFileName);
if (m_lpBgImgH != NULL)
m_lpBgImgH->SetNinePart(lpNinePart);
return (m_lpBgImgH != NULL) ? TRUE : FALSE;
}
BOOL CSkinComboBox::SetArrowNormalPic(LPCTSTR lpszFileName)
{
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgN);
m_lpArrowImgN = CSkinManager::GetInstance()->GetImage(lpszFileName);
return (m_lpArrowImgN != NULL) ? TRUE : FALSE;
}
BOOL CSkinComboBox::SetArrowHotPic(LPCTSTR lpszFileName)
{
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgH);
m_lpArrowImgH = CSkinManager::GetInstance()->GetImage(lpszFileName);
return (m_lpArrowImgH != NULL) ? TRUE : FALSE;
}
BOOL CSkinComboBox::SetArrowPushedPic(LPCTSTR lpszFileName)
{
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgP);
m_lpArrowImgP = CSkinManager::GetInstance()->GetImage(lpszFileName);
return (m_lpArrowImgP != NULL) ? TRUE : FALSE;
}
void CSkinComboBox::SetTransparent(BOOL bTransparent, HDC hBgDC)
{
m_bTransparent = bTransparent;
m_hBgDC = hBgDC;
}
void CSkinComboBox::SetDefaultText(LPCTSTR lpszText)
{
m_Edit.SetDefaultText(lpszText);
}
BOOL CSkinComboBox::IsDefaultText()
{
return m_Edit.IsDefaultText();
}
// 设置上下左右边距函数
void CSkinComboBox::SetMarginsEx(int nLeft, int nTop, int nRight, int nBottom)
{
// CRect rtClient;
// GetClientRect(rtClient);
//
// CRect rt(rtClient.left + nLeft, rtClient.top + nTop,
// rtClient.right - nRight, rtClient.bottom - nBottom);
// SetRectNP(rt);
}
void CSkinComboBox::SetArrowWidth(int nWidth)
{
m_nArrowWidth = nWidth;
}
BOOL CSkinComboBox::SubclassWindow(HWND hWnd)
{
BOOL bRet = __super::SubclassWindow(hWnd);
COMBOBOXINFO stComboBoxInfo;
stComboBoxInfo.cbSize = sizeof(stComboBoxInfo);
GetComboBoxInfo(&stComboBoxInfo);
m_Edit.SetOwnerWnd(m_hWnd);
m_Edit.SubclassWindow(stComboBoxInfo.hwndItem);
m_ListBox.SetOwnerWnd(m_hWnd);
m_ListBox.SubclassWindow(stComboBoxInfo.hwndList);
return TRUE;
}
int CSkinComboBox::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
SetMsgHandled(FALSE);
return 0;
}
BOOL CSkinComboBox::OnEraseBkgnd(CDCHandle dc)
{
return TRUE;
}
void CSkinComboBox::OnPaint(CDCHandle dc)
{
CPaintDC PaintDC(m_hWnd);
HDC hDC = PaintDC.m_hDC;
CRect rcClient;
GetClientRect(&rcClient);
CRect rcArrow;
HRGN hRgn2 = NULL;
if (m_lpArrowImgN != NULL && !m_lpArrowImgN->IsNull())
{
int cxIcon = m_nArrowWidth;
int cyIcon = m_lpArrowImgN->GetHeight();
CalcCenterRect(rcClient, cxIcon, cyIcon, rcArrow);
rcArrow.right = rcClient.right - 2;
rcArrow.left = rcArrow.right - cxIcon;
}
//PaintDC.FillSolidRect(rcClient, RGB(255, 255, 255));
if (m_bTransparent)
DrawParentWndBg(hDC);
if (m_bHover)
{
if (m_lpBgImgH != NULL && !m_lpBgImgH->IsNull())
{
m_lpBgImgH->Draw2(hDC, rcClient);
}
else
{
if (m_lpBgImgN != NULL && !m_lpBgImgN->IsNull())
m_lpBgImgN->Draw2(hDC, rcClient);
}
}
else
{
if (m_lpBgImgN != NULL && !m_lpBgImgN->IsNull())
m_lpBgImgN->Draw2(hDC, rcClient);
}
if (m_bArrowPress)
{
if (m_lpArrowImgP != NULL && !m_lpArrowImgP->IsNull())
m_lpArrowImgP->Draw2(hDC, rcArrow);
}
else if (m_bArrowHover)
{
if (m_lpArrowImgH != NULL && !m_lpArrowImgH->IsNull())
m_lpArrowImgH->Draw2(hDC, rcArrow);
}
else
{
if (m_lpArrowImgN != NULL && !m_lpArrowImgN->IsNull())
m_lpArrowImgN->Draw2(hDC, rcArrow);
}
}
void CSkinComboBox::OnLButtonDown(UINT nFlags, CPoint point)
{
//SetMsgHandled(FALSE);
if (m_rcArrow.PtInRect(point))
{
if (!m_ListBox.IsWindowVisible())
{
m_bArrowPress = TRUE;
Invalidate();
ShowDropDown(TRUE);
}
}
}
void CSkinComboBox::OnLButtonUp(UINT nFlags, CPoint point)
{
//SetMsgHandled(FALSE);
// if (m_bPress)
// {
// m_bPress = FALSE;
// ::InvalidateRect(m_hWnd, NULL, TRUE);
// }
}
void CSkinComboBox::OnMouseMove(UINT nFlags, CPoint point)
{
//SetMsgHandled(FALSE);
BOOL bRePaint = FALSE;
if (!m_bMouseTracking)
{
StartTrackMouseLeave();
m_bMouseTracking = TRUE;
m_bHover = TRUE;
bRePaint = TRUE;
}
if (m_rcArrow.PtInRect(point))
{
if (!m_bArrowHover)
{
m_bArrowHover = TRUE;
bRePaint = TRUE;
}
}
else
{
if (m_bArrowHover)
{
m_bArrowHover = FALSE;
bRePaint = TRUE;
}
}
if (bRePaint)
Invalidate();
}
void CSkinComboBox::OnMouseLeave()
{
//SetMsgHandled(FALSE);
m_bMouseTracking = FALSE;
if (!m_ListBox.IsWindowVisible())
{
CPoint pt;
GetCursorPos(&pt);
CRect rcWindow;
GetWindowRect(&rcWindow);
if (!rcWindow.PtInRect(pt))
m_bHover = FALSE;
m_bArrowHover = FALSE;
Invalidate();
}
}
void CSkinComboBox::OnDestroy()
{
SetMsgHandled(FALSE);
CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgN);
CSkinManager::GetInstance()->ReleaseImage(m_lpBgImgH);
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgN);
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgH);
CSkinManager::GetInstance()->ReleaseImage(m_lpArrowImgP);
}
void CSkinComboBox::OnSize(UINT nType, CSize size)
{
DefWindowProc();
CRect rcClient;
GetClientRect(&rcClient);
CRect rcEdit;
m_Edit.GetWindowRect(&rcEdit);
ScreenToClient(&rcEdit);
CDCHandle dc = m_Edit.GetDC();
TEXTMETRIC tm = {0};
dc.GetTextMetrics(&tm);
int nFontHeight = tm.tmHeight + tm.tmExternalLeading;
int nMargin = (rcEdit.Height() - nFontHeight) / 2;
m_Edit.ReleaseDC(dc);
rcEdit.DeflateRect(0, nMargin);
rcEdit.right = rcClient.right - 2 - m_nArrowWidth;
m_Edit.MoveWindow(&rcEdit, FALSE);
m_rcArrow.left = rcClient.right - 2 - m_nArrowWidth;
m_rcArrow.right = m_rcArrow.left + m_nArrowWidth;
m_rcArrow.top = rcClient.top;
m_rcArrow.bottom = rcClient.bottom;
}
LRESULT CSkinComboBox::OnEditMouseHover(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
if (!m_bHover)
{
m_bHover = TRUE;
Invalidate();
}
return 0;
}
LRESULT CSkinComboBox::OnEditMouseLeave(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
CPoint pt;
GetCursorPos(&pt);
CRect rcWindow;
GetWindowRect(&rcWindow);
if (!rcWindow.PtInRect(pt))
{
if (m_bHover)
{
m_bHover = FALSE;
Invalidate();
}
}
return 0;
}
LRESULT CSkinComboBox::OnListHide(UINT uMsg, WPARAM wParam, LPARAM lParam)
{
m_bHover = FALSE;
m_bArrowHover = FALSE;
m_bArrowPress = FALSE;
Invalidate();
return 0;
}
BOOL CSkinComboBox::StartTrackMouseLeave()
{
TRACKMOUSEEVENT tme = { 0 };
tme.cbSize = sizeof(tme);
tme.dwFlags = TME_LEAVE;
tme.hwndTrack = m_hWnd;
return _TrackMouseEvent(&tme);
}
void CSkinComboBox::CalcCenterRect(CRect& rcDest, int cx, int cy, CRect& rcCenter)
{
int x = (rcDest.Width() - cx + 1) / 2;
int y = (rcDest.Height() - cy + 1) / 2;
rcCenter = CRect(rcDest.left+x, rcDest.top+y, rcDest.left+x+cx, rcDest.top+y+cy);
}
void CSkinComboBox::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);
}