2010. 11. 1. 10:19
CBitmapButton의 투명(Transparent)와 Hover 지원하기
2010. 11. 1. 10:19 in 프로그래밍/Let's Share it
CBitmapButton의 최대 단점중 하나는 (혹은 많은 요구사항중 하나는),
- 투명 처리 (Transparent)
- Hover Button 처리 (마우스 커서가 위(OnMouse)일때, 다른 Bitmap 처리하기)
입니다.
물론, 더 확장된 내용은 CodeProject등에 CButtonst등이 있는걸로 아는데, 굉장히 복잡도가 높습니다.
그래서, 한번 MFC의 CBitmapButton class를 살펴보니, CBitmapButton::DrawItem(...)이 재정의 된걸 확인하였습니다. 아차~! CBitmapButton::DrawItem(...)의 BitBlt(...)를 BitBltTransparent(...)로 변경하면 쉽게 투명 처리가 되겠구나 했습니다.
// CBitmapButton - push-button with 1->4 bitmap images class CBitmapButton : public CButton { ... virtual void DrawItem(LPDRAWITEMSTRUCT lpDIS); }; void CBitmapButton::DrawItem(LPDRAWITEMSTRUCT lpDIS) { ... pDC->BitBlt(rect.left, rect.top, rect.Width(), rect.Height(), &memDC, 0, 0, SRCCOPY); ... }
즉, 위의 BitBlt(...)를 BitBltTransparent(...)로 변경하면 작업은 끝나는 겁니다.
그리고, Hover Button을 위해서는, WM_MOUSELEAVE/_TrackMouseEvent(...)를 통해 쉽게 해결이 됩니다.
그럼 CBitmapButtonTrans class의 사용예는 다음과 같습니다.
// header file #include "bitmapbuttontrans.h" class C~ : public CView / CDialog / CMainFrame / ... { ... private: CBitmapButtonTrans m_cBtn; } // c++ file int C~::OnCreate(LPCREATESTRUCT lpCreateStruct) // OnCreate, OnInitDialog Timing { if (C~::OnCreate(lpCreateStruct) == -1) return -1; ... m_cBtn.Create(TEXT(""), WS_CHILD|WS_VISIBLE|BS_OWNERDRAW, CRect(x,y,xx,yy), this, -1); m_cBtn.LoadBitmaps(IDB_BITMAP_1, IDB_BITMAP_2, IDB_BITMAP_3, IDB_BITMAP_4); m_cBtn.SizeToContent(); m_cBtn.SetHoverBitmapID(IDB_BITMAP_5); m_cBtn.SetTransBitmap(RGB(255,0,255)); ... }
와 같습니다. 만일, CDialog 기반이라면, 위 m_cBtn.Create(...)등은 필요없습니다.
일반적인 기능은 CBitmapButton과 동일합니다. 다만, SetHoverBitmapID(...)와 SetTransBitmap(...)이 추가되었습니다. SetHoverBitmapID(...)는 OnMouse일때 표시될 BITMAP ID입니다. 그리고, SetTransBitmap(...)은 투명처리할 Bitmap의 color입니다. 만일 CMainFrame, CView 기반이라면, .Create(..., -1)에 -1 부분에 실제 ID를 넣어, ON_COMMAND 처리를 해줘야 합니다.
소스 코드를 공유합니다. (view plain link를 누르시면 제대로된 코드를 확인할 수 있습니다.)
bitmapbuttontrans.h
#pragma once // CBitmapButtonTrans class CBitmapButtonTrans : public CBitmapButton { DECLARE_DYNAMIC(CBitmapButtonTrans) public: CBitmapButtonTrans(); virtual ~CBitmapButtonTrans(); virtual VOID SetTransBitmap(IN COLORREF clrTrans) {m_clrTrans = clrTrans;} virtual VOID SetHoverBitmapID(IN UINT nIDBitmapResourceHover); protected: COLORREF m_clrTrans; BOOL m_bMouseHover; TRACKMOUSEEVENT m_stTrackMouse; UINT m_nIDBitmapResourceHover; CBitmap m_cBitmapHover; protected: DECLARE_MESSAGE_MAP() public: virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/); afx_msg BOOL OnEraseBkgnd(CDC* pDC); afx_msg void OnMouseMove(UINT nFlags, CPoint point); afx_msg void OnMouseLeave(); afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct); };
bitmapbuttontrans.cpp
// BitmapButtonTrans.cpp : implementation file // #include "stdafx.h" #include "LayoutMgr.h" #include "BitmapButtonTrans.h" // CBitmapButtonTrans IMPLEMENT_DYNAMIC(CBitmapButtonTrans, CBitmapButton) CBitmapButtonTrans::CBitmapButtonTrans() { m_clrTrans = RGB(255,0,255); m_bMouseHover = FALSE; m_nIDBitmapResourceHover= 0; ZeroMemory(&m_stTrackMouse, sizeof(m_stTrackMouse)); } CBitmapButtonTrans::~CBitmapButtonTrans() { } BEGIN_MESSAGE_MAP(CBitmapButtonTrans, CBitmapButton) ON_WM_ERASEBKGND() ON_WM_MOUSEMOVE() ON_WM_MOUSELEAVE() ON_WM_CREATE() END_MESSAGE_MAP() // CBitmapButtonTrans message handlers void CBitmapButtonTrans::DrawItem(LPDRAWITEMSTRUCT lpDIS) { ASSERT(lpDIS != NULL); // must have at least the first bitmap loaded before calling DrawItem ASSERT(m_bitmap.m_hObject != NULL); // required // use the main bitmap for up, the selected bitmap for down CBitmap* pBitmap = &m_bitmap; UINT state = lpDIS->itemState; if ((state & ODS_SELECTED) && m_bitmapSel.m_hObject != NULL) pBitmap = &m_bitmapSel; else if ((state & ODS_FOCUS) && m_bitmapFocus.m_hObject != NULL) pBitmap = &m_bitmapFocus; // third image for focused else if ((state & ODS_DISABLED) && m_bitmapDisabled.m_hObject != NULL) pBitmap = &m_bitmapDisabled; // last image for disabled if ((TRUE == m_bMouseHover) && NULL != m_cBitmapHover.GetSafeHandle()) { pBitmap = &m_cBitmapHover; } // draw the whole button CDC* pDC = CDC::FromHandle(lpDIS->hDC); CRect rect; rect.CopyRect(&lpDIS->rcItem); CLayoutMgr::DrawBitmapTrans(pDC, pBitmap, rect.left, rect.top, m_clrTrans); } BOOL CBitmapButtonTrans::OnEraseBkgnd(CDC* pDC) { return FALSE; } void CBitmapButtonTrans::OnMouseMove(UINT nFlags, CPoint point) { if (FALSE == m_bMouseHover) { ::_TrackMouseEvent(&m_stTrackMouse); m_bMouseHover = TRUE; Invalidate(FALSE); } CBitmapButton::OnMouseMove(nFlags, point); } void CBitmapButtonTrans::OnMouseLeave() { m_bMouseHover = FALSE; Invalidate(FALSE); CBitmapButton::OnMouseLeave(); } VOID CBitmapButtonTrans::SetHoverBitmapID(IN UINT nIDBitmapResourceHover) { m_nIDBitmapResourceHover = nIDBitmapResourceHover; if (0 != m_nIDBitmapResourceHover) { m_cBitmapHover.DeleteObject(); m_cBitmapHover.LoadBitmap(m_nIDBitmapResourceHover); } } int CBitmapButtonTrans::OnCreate(LPCREATESTRUCT lpCreateStruct) { if (CBitmapButton::OnCreate(lpCreateStruct) == -1) return -1; m_stTrackMouse.cbSize = sizeof(TRACKMOUSEEVENT); m_stTrackMouse.dwFlags = TME_LEAVE; m_stTrackMouse.dwHoverTime = HOVER_DEFAULT; m_stTrackMouse.hwndTrack = GetSafeHwnd(); return 0; }
layoutmgr.h / layoutmgr.cpp (유틸리티 class인데, CBitmapButtonTrans에 넣으셔도 됩니다)
// header class CLayoutMgr { ... public: static VOID DrawBitmapTrans(IN OUT CDC* pDC, IN CBitmap* pcBitmap, IN int x, IN int y, IN COLORREF crMask); ... } // cpp file VOID CLayoutMgr::DrawBitmapTrans(IN OUT CDC* pDC, IN CBitmap* pcBitmap, IN int x, IN int y, IN COLORREF crMask) { CBitmap *pOldBitmapImage = NULL; CBitmap *pOldBitmapTrans = NULL; COLORREF clrOldBack = 0; COLORREF clrOldText = 0; BITMAP bm = {0,}; CDC dcImage; CDC dcTrans; CBitmap bitmapTrans; if ((NULL == pcBitmap) || (NULL == pDC)) { return; } pcBitmap->GetBitmap(&bm); dcImage.CreateCompatibleDC( pDC ); pOldBitmapImage = dcImage.SelectObject( pcBitmap ); clrOldBack = pDC->SetBkColor( RGB( 255, 255, 255 ) ); clrOldText = pDC->SetTextColor( RGB( 0, 0, 0 ) ); dcTrans.CreateCompatibleDC( pDC ); bitmapTrans.CreateBitmap( bm.bmWidth, bm.bmHeight, 1, 1, NULL ); pOldBitmapTrans = dcTrans.SelectObject( &bitmapTrans ); dcImage.SetBkColor( crMask ); dcTrans.BitBlt( 0, 0, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCCOPY ); pDC->BitBlt( x, y, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCINVERT ); pDC->BitBlt( x, y, bm.bmWidth, bm.bmHeight, &dcTrans, 0, 0, SRCAND ); pDC->BitBlt( x, y, bm.bmWidth, bm.bmHeight, &dcImage, 0, 0, SRCINVERT ); dcTrans.SelectObject( pOldBitmapTrans ); pDC->SetBkColor( clrOldBack ); pDC->SetTextColor( clrOldText ); bitmapTrans.DeleteObject(); dcTrans.DeleteDC(); dcImage.SelectObject( pOldBitmapImage ); dcImage.DeleteDC(); }
'프로그래밍 > Let's Share it' 카테고리의 다른 글
CHtmlView의 C++에서 생성한 JScript를 모든 Frame에 대해 Inject하여 실행하기 (1) | 2010.12.08 |
---|---|
CHtmlView의 C++에서 생성한 JScript를 Inject하여 실행하기 (0) | 2010.11.03 |
Crash 발생시 스스로 미니 덤프를 생성하는 코드 공유와 간략한 덤프 분석 방법 (1) | 2009.09.25 |
IOCP를 이용한 Thread Safe Job Queue (3) | 2009.09.24 |
CListCtrl의 내용을 프린터로 출력하기 (2) | 2009.09.23 |