MFC(2)Buttonコントロール自己描画実装

9191 ワード

まずMFCのCButtonクラスのソースコードを見てみましょう.ボタンがインタフェースとよく一致する必要がある場合、1つの方法はCButtonクラスの関数パラメータを設定することであり、もう1つの方法はCButtonクラスを模倣して新しいクラスを設計し、Buttonの自己描画を実現することである.
CButtonクラスのソースコードは以下の通りです.
class CButton : public CWnd { 	DECLARE_DYNAMIC(CButton)  // Constructors public: 	CButton(); 	virtual BOOL Create(LPCTSTR lpszCaption, DWORD dwStyle, 				const RECT& rect, CWnd* pParentWnd, UINT nID);  // Attributes 	UINT GetState() const; 	void SetState(BOOL bHighlight); 	int GetCheck() const; 	void SetCheck(int nCheck); 	UINT GetButtonStyle() const; 	void SetButtonStyle(UINT nStyle, BOOL bRedraw = TRUE);  	HICON SetIcon(HICON hIcon); 	HICON GetIcon() const; 	HBITMAP SetBitmap(HBITMAP hBitmap); 	HBITMAP GetBitmap() const; 	HCURSOR SetCursor(HCURSOR hCursor); 	HCURSOR GetCursor();  #if (_WIN32_WINNT >= 0x501) 	AFX_ANSI_DEPRECATED BOOL GetIdealSize(_Out_ LPSIZE psize) const; 	AFX_ANSI_DEPRECATED BOOL SetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist); 	AFX_ANSI_DEPRECATED BOOL GetImageList(_In_ PBUTTON_IMAGELIST pbuttonImagelist) const; 	AFX_ANSI_DEPRECATED BOOL SetTextMargin(_In_ LPRECT pmargin); 	AFX_ANSI_DEPRECATED BOOL GetTextMargin(_Out_ LPRECT pmargin) const; #endif  // (_WIN32_WINNT >= 0x501)  #if ( _WIN32_WINNT >= 0x0600 ) && defined(UNICODE) 	CString GetNote() const; 	_Check_return_ BOOL GetNote(_Out_z_cap_(*pcchNote) LPTSTR lpszNote, _Inout_ UINT* pcchNote) const; 	BOOL SetNote(_In_z_ LPCTSTR lpszNote); 	UINT GetNoteLength() const; 	BOOL GetSplitInfo(_Out_ PBUTTON_SPLITINFO pInfo) const; 	BOOL SetSplitInfo(_In_ PBUTTON_SPLITINFO pInfo); 	UINT GetSplitStyle() const; 	BOOL SetSplitStyle(_In_ UINT nStyle); 	BOOL GetSplitSize(_Out_ LPSIZE pSize) const; 	BOOL SetSplitSize(_In_ LPSIZE pSize); 	CImageList* GetSplitImageList() const; 	BOOL SetSplitImageList(_In_ CImageList* pSplitImageList); 	TCHAR GetSplitGlyph() const; 	BOOL SetSplitGlyph(_In_ TCHAR chGlyph); 	BOOL SetDropDownState(_In_ BOOL fDropDown);  	// Sets whether the action associated with the button requires elevated permissions. 	// If elevated permissions are required then the button should display an elevated icon. 	HICON SetShield(_In_ BOOL fElevationRequired); #endif // ( _WIN32_WINNT >= 0x600 ) && defined(UNICODE)  // Overridables (for owner draw only) 	virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);  // Implementation public: 	virtual ~CButton(); protected: 	virtual BOOL OnChildNotify(UINT, WPARAM, LPARAM, LRESULT*); }; 

自己描画VincentButtonクラスは次のとおりです.
#ifndef _VINCENT_BUTTON_H_ #define _VINCENT_BUTTON_H_  class VincentButton : public CButton { public: 	VincentButton(); 	virtual ~VincentButton();      //   	virtual void GradientFill(CDC *pDC, CRect* rect);      //   	virtual void DrawBorder(CDC *pDC, CRect* rect);      //  CButton      virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);  protected:     virtual void PreSubclassWindow();      // MFC   	afx_msg void OnMouseMove(UINT nFlags, CPoint point); 	afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam); 	afx_msg LRESULT OnMouseHover(WPARAM wParam, LPARAM lParam); 	afx_msg void OnLButtonDown(UINT nFlags, CPoint point);     afx_msg void OnLButtonUp(UINT nFlags, CPoint point);   protected: 	DECLARE_MESSAGE_MAP()  public:     //       CPen m_penBorderNormal;     //       CPen m_penBorderOnFocus;     //       bool m_bMouseOn;        //       bool m_bMouseClick;     //       bool m_bMouseUp;        //       bool m_bFocus;          //        CRect m_rect; };  #endif
// VincentButton.cpp : implementation file //  #include "stdafx.h" #include "VincentButton.h"  #ifdef _DEBUG #define new DEBUG_NEW #endif  VincentButton::VincentButton() {     m_penBorderNormal.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0x23, 0xC5, 0xCE));     m_penBorderOnFocus.CreatePen(PS_INSIDEFRAME | PS_SOLID, 1, RGB(0xFF, 0x00, 0xFF));      m_bMouseOn = false;     m_bMouseClick = false;     m_bMouseUp = true;     m_bFocus = false; }  VincentButton::~VincentButton() {     m_penBorderNormal.DeleteObject();     m_penBorderOnFocus.DeleteObject(); }   BEGIN_MESSAGE_MAP(VincentButton, CButton)     ON_WM_MOUSEMOVE()     ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave)     ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover)     ON_WM_LBUTTONDOWN()     ON_WM_LBUTTONUP() END_MESSAGE_MAP()  #pragma warning(push) #pragma warning(disable:4800) void VincentButton::OnMouseMove(UINT nFlags, CPoint point) {     if (!m_bMouseUp)     {         TRACKMOUSEEVENT tme;          tme.cbSize = sizeof(tme);         tme.hwndTrack = m_hWnd;         tme.dwFlags = TME_LEAVE | TME_HOVER;         tme.dwHoverTime = 1;          m_bMouseOn = _TrackMouseEvent(&tme);     }      CButton::OnMouseMove(nFlags, point); } #pragma warning(pop)  LRESULT VincentButton::OnMouseLeave(WPARAM wParam, LPARAM lParam) {     m_bMouseOn = false;      InvalidateRect(NULL);      return 0; }  LRESULT VincentButton::OnMouseHover(WPARAM wParam, LPARAM lParam) {     m_bMouseOn = true;      InvalidateRect(NULL, FALSE);      return 0; }  void VincentButton::OnLButtonDown(UINT nFlags, CPoint point) {     m_bMouseOn = true;     m_bMouseUp = false;     m_bMouseClick = true;     m_bFocus = true;       InvalidateRect(NULL, FALSE);      CButton::OnLButtonDown(nFlags, point); }  void VincentButton::OnLButtonUp(UINT nFlags, CPoint point) {     m_bMouseUp = true;     m_bMouseOn = false;     m_bMouseClick = true;     m_bFocus = true;      InvalidateRect(NULL, FALSE);      CButton::OnLButtonUp(nFlags, point); }   void VincentButton::GradientFill(CDC *pDC, CRect* rect) {     BYTE r = 34;     BYTE g = 180;     BYTE b = 227;      CPen *temp = new CPen;     CPen *pOldPen = pDC->SelectObject(temp);      LONG nMiddle = (rect->bottom - rect->top) / 2;     LONG i = 0;      for (i = nMiddle; i > rect->top; --i)     {         CPen pen(PS_INSIDEFRAME | PS_SOLID, 1,             RGB(r + 10 * (nMiddle - i), g + 2 * (nMiddle - i), b + (nMiddle - i)));          pDC->SelectObject(&pen);         pDC->MoveTo(rect->left, i);         pDC->LineTo(rect->right, i);     }      for (i = nMiddle; i < rect->bottom; ++i)     {         CPen pen(PS_INSIDEFRAME | PS_SOLID, 1,             RGB(r + 10 * (i - nMiddle), g + 2 * (i - nMiddle), b + (i - nMiddle)));          pDC->SelectObject(&pen);         pDC->MoveTo(rect->left, i);         pDC->LineTo(rect->right, i);     }      delete temp;      pDC->SelectObject(pOldPen); }   void VincentButton::DrawBorder(CDC *pDC, CRect* rect) {     CPen *pOldPen ;     CPoint oldPoint = pDC->MoveTo(rect->left, rect->bottom - 1);       if (m_bFocus || m_bMouseOn)     {         pOldPen = pDC->SelectObject(&m_penBorderOnFocus);     }     else     {         pOldPen = pDC->SelectObject(&m_penBorderNormal);     }      pDC->MoveTo(rect->left, rect->top);     pDC->LineTo(rect->right - 1, rect->top);     pDC->LineTo(rect->right - 1, rect->bottom - 1);     pDC->LineTo(rect->left, rect->bottom - 1);     pDC->LineTo(rect->left, rect->top);     pDC->MoveTo(oldPoint);      pDC->SelectObject(pOldPen); }  void VincentButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct) {     CRect rect =  lpDrawItemStruct->rcItem;     CDC *pDC=CDC::FromHandle(lpDrawItemStruct->hDC);     int nSaveDC=pDC->SaveDC();     UINT state = lpDrawItemStruct->itemState;     TCHAR strText[MAX_PATH + 1];     ::GetWindowText(m_hWnd, strText, MAX_PATH);      CPen* hOldPen = pDC->SelectObject(&m_penBorderNormal);      if (state & ODS_FOCUS)     {         m_bFocus = true;         m_bMouseClick = true;     }     else     {         m_bFocus = false;         m_bMouseClick = false;     }      if (state & ODS_SELECTED || state & ODS_DEFAULT)     {         m_bFocus = true;     }      pDC->SelectObject(hOldPen);      if (m_bMouseOn)     {         hOldPen = pDC->SelectObject(&m_penBorderOnFocus);          GradientFill(pDC, &rect);     }     else     {         hOldPen = pDC->SelectObject(&m_penBorderNormal);          GradientFill(pDC, &rect);     }           pDC->SelectObject(hOldPen);     DrawBorder(pDC, &m_rect);      //      if (strText!=NULL)     {         pDC->SetTextColor(RGB(0x3A, 0x5F, 0xCD));         CFont* hFont = GetFont();         CFont* hOldFont = pDC->SelectObject(hFont);         CSize szExtent = pDC->GetTextExtent(strText, lstrlen(strText));         CPoint pt( rect.CenterPoint().x - szExtent.cx / 2, rect.CenterPoint().y - szExtent.cy / 2);         if (state & ODS_SELECTED)              pt.Offset(1, 1);         int nMode = pDC->SetBkMode(TRANSPARENT);         if (state & ODS_DISABLED)             pDC->DrawState(pt, szExtent, strText, DSS_DISABLED, TRUE, 0, (HBRUSH)NULL);         else             pDC->DrawState(pt, szExtent, strText, DSS_NORMAL, TRUE, 0, (HBRUSH)NULL);         pDC->SelectObject(hOldFont);         pDC->SetBkMode(nMode);     }      pDC->RestoreDC(nSaveDC); }  void VincentButton::PreSubclassWindow() {     ModifyStyle(0, BS_OWNERDRAW);      GetClientRect(&m_rect);      CButton::PreSubclassWindow(); }