오너 드로우 버튼은 기능적으로는 버튼 컨트롤이지만 화면에 보이는 외관은 모두 다시 그려지게 된다. 여기서 그린다는 표현은 GDI 기법을 이용해 버튼의 색상이나 선 하나하나를 모두 그린다는 의미이며, 오너 드로우 기법은 버튼 컨트롤에만 적용되는 것이 아니라 대부분의 컨트롤 윈도우에서 속성을 통해 지원하며, 그리기가 이루어지는  MFC 가상 함수는 DrawItem() 함수다.

그리고 MFC 에서 오너 드로우 버튼을 직접 개발하는 일은 기본적으로 서브 클래싱을 전제로 하며, 앞서 설명한 방식보다 지금부터 실습할 기법을 주로 의미한다. 다음 예제는 비트맵 이미지를 이용하여 버튼 컨트롤을 구현한 예이다.


// ImageButton.cpp : 구현 파일입니다.
//

#include "stdafx.h"
#include "ImageButtonDemo2.h"
#include "ImageButton.h"


// CImageButton

IMPLEMENT_DYNAMIC(CImageButton, CButton)

CImageButton::CImageButton()
{
 m_bHover = false;
 m_bTracking = false;
}

CImageButton::~CImageButton()
{
}


BEGIN_MESSAGE_MAP(CImageButton, CButton)
 ON_WM_MOUSEMOVE()
 ON_WM_MOUSEHOVER()
 ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()

 

// CImageButton 메시지 처리기입니다.

 

void CImageButton::OnMouseMove(UINT nFlags, CPoint point)
{

 if(!m_bTracking)
 {
  TRACKMOUSEEVENT tme;
  ::ZeroMemory(&tme, sizeof(tme));

  tme.cbSize = sizeof(tme);
  tme.hwndTrack = m_hWnd;
  tme.dwFlags = TME_LEAVE | TME_HOVER;
  tme.dwHoverTime = 1;

  m_bTracking = ::_TrackMouseEvent(&tme);

  // 마우스 이벤트를 추적하기 시작하면 m_bTracking 멤버가 true 가 되며,
  //조건을 만족하는 경우는 아직 이벤트를 추적하지 않은 상태에서 마우스 메시지가 발생한 경우이다.
  //그리고 추적할 메시지는 MOUSEHOVER와 MOUSELEAVE 메시지이므로 FLAG값을 HOVER와 LEAVE로 설정했다.

 }
 CButton::OnMouseMove(nFlags, point);
}

void CImageButton::OnMouseHover(UINT nFlags, CPoint point)
{
 // TODO: 여기에 메시지 처리기 코드를 추가 및/또는 기본값을 호출합니다.
 m_bHover = true;
 RedrawWindow(NULL,NULL, RDW_INVALIDATE | RDW_UPDATENOW);


 CButton::OnMouseHover(nFlags, point);
}

void CImageButton::OnMouseLeave()
{
 m_bHover = false;
 m_bTracking = false;
 RedrawWindow(NULL,NULL,RDW_INVALIDATE | RDW_UPDATENOW);

 CButton::OnMouseLeave();
}

void CImageButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

 CDC *pDC = CDC::FromHandle(lpDrawItemStruct->hDC);

 CDC MemDC;
 MemDC.CreateCompatibleDC(pDC);

 CBitmap Bmp;
 Bmp.LoadBitmap(IDB_Button_Image);
 CBitmap* pOldBitmap = MemDC.SelectObject(&Bmp);
 
 if(lpDrawItemStruct->itemState & ODS_SELECTED)
 {
  pDC->BitBlt(0,0,40,40, &MemDC , 40,0, SRCCOPY);
 }
 else
 {
  if(m_bHover) pDC->BitBlt(0,0,40,40, &MemDC, 80,0, SRCCOPY);
  else   pDC->BitBlt(0,0,40,40,&MemDC, 0,0, SRCCOPY);
 }
 MemDC.SelectObject(pOldBitmap);
}
------------------------------------------------------------------------------------



#pragma once


// CImageButton

class CImageButton : public CButton
{
 DECLARE_DYNAMIC(CImageButton)

public:
 CImageButton();
 virtual ~CImageButton();

protected:
 DECLARE_MESSAGE_MAP()

public:
 bool m_bHover;
 bool m_bTracking;

 afx_msg void OnMouseMove(UINT nFlags, CPoint point);
 afx_msg void OnMouseHover(UINT nFlags, CPoint point);
 afx_msg void OnMouseLeave();
 virtual void DrawItem(LPDRAWITEMSTRUCT /*lpDrawItemStruct*/);
};

------------------------------------------------------------------------------------


// ImageButtonDemo2Dlg.h : 헤더 파일
//

#pragma once
#include "afxwin.h"
#include "ImageButton.h"

// CImageButtonDemo2Dlg 대화 상자
class CImageButtonDemo2Dlg : public CDialog
{
// 생성입니다.
public:
 CImageButtonDemo2Dlg(CWnd* pParent = NULL); // 표준 생성자입니다.

// 대화 상자 데이터입니다.
 enum { IDD = IDD_IMAGEBUTTONDEMO2_DIALOG };

 protected:
 virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 지원입니다.


// 구현입니다.
protected:
 HICON m_hIcon;

 // 생성된 메시지 맵 함수
 virtual BOOL OnInitDialog();
 afx_msg void OnSysCommand(UINT nID, LPARAM lParam);
 afx_msg void OnPaint();
 afx_msg HCURSOR OnQueryDragIcon();
 DECLARE_MESSAGE_MAP()
public:
 CImageButton m_Btn_Image; // 앞으로 작성할 새로운 클래스는 CButton 클래스의 파생 클래스이며, 이 코드가 변하게 된다.
};
------------------------------------------------------------------------------------

CButton 클래스의 DrawItem() 메서드의 인자로 DRAWITEMSTRUCT 구조체가 전달된다.












+ Recent posts