MFC 之 重绘按键Cbutton
上次我們學習了如何美化對話框的界面,這次我們為上次的對話框添加兩個按鈕,一個是關閉按鈕,另一個是最小化按鈕,好,現在我們先看一下效果:
是不是很難看,因為我們的對話框美化了,所以我們的按鈕也要美化,因為采用貼圖的方式來美化,所以,我先給出這兩個按鈕的PNG格式的圖片,該圖片支持透明色,具體如下:
關閉按鈕效果圖:
最小化按鈕效果圖:
這兩張效果圖是我自己從網上找的,可能不是很合適,但是用來教學,完全沒有問題,它們的尺寸都是108*21,每張圖片都有四個小圖片,第一張和第四張小圖片都是透明的,所以看不見效果,我們使用這兩張圖片來完成按鈕的美化,每張圖片從左向右有四張小圖片,我們只用前三張,分別對應默認狀態,焦點狀態,按下狀態。
下面,我們來說一下如何美化按鈕?
第1步,我們先在對話框上放置兩個按鈕,一個是關閉按鈕,另一個是最小化按鈕,它們對應的ID分別是IDC_BUTTON_CLOSE和IDC_BUTTON_MIN,然后將我們的按鈕設置為自繪制模式,方法如下:
選擇按鈕,右鍵屬性,在屬性列表中找到Owner Draw選項,將其設置為True,效果圖如下:
再為它們添加兩個成員變量,具體如下:
CButton m_btnClose;
CButton m_btnMin;
第2步,我們新建一個類,繼承自CButton,我們取名為CMyButton,為其添加3個成員變量,分別如下:
//按鈕背景圖像
CImage m_imgButton;
//按鈕png路徑,包括焦點,正常,按下3個狀態
CString m_strImgPath;
//父窗口背景圖片背景路徑,透明png需要使用
CString m_strImgParentPath;
第3步,我們為CMyButton添加3個成員函數,分別如下:
//設置按鈕背景圖片路徑,父窗口背景圖片路徑
void SetImagePath(CString strImgPath, CString strParentImgPath);
//初始化按鈕,主要是調整按鈕的位置,處理透明色
bool InitMyButton(int nX/*左上角X坐標*/, int nY/*左上角Y坐標*/,int nW/*圖像寬*/, int nH/*圖像高*/, bool bIsPng/*是否是PNG圖片*/);
//自繪制函數
void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
CMyButton的聲明最終如下:
class CMyButton : public CButton
{
????DECLARE_DYNAMIC(CMyButton)
?
public:
????CMyButton();
?
????virtual ~CMyButton();
????
????//按鈕背景圖像
????CImage m_imgButton;
?
????//按鈕png路徑,包括焦點,正常,按下3個狀態
????CString m_strImgPath;
?
????//父窗口背景圖片背景路徑,透明png需要使用
????CString m_strImgParentPath;
?
????//設置按鈕背景圖片路徑,父窗口背景圖片路徑
????void SetImagePath(CString strImgPath, CString strParentImgPath);
?
????//初始化按鈕,主要是調整按鈕的位置,處理透明色
????bool InitMyButton(int nX/*左上角X坐標*/, int nY/*左上角Y坐標*/,int nW/*圖像寬*/, int nH/*圖像高*/, bool bIsPng/*是否是PNG圖片*/);
?
????//自繪制函數
????void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
?
protected:
????DECLARE_MESSAGE_MAP()
};
第4步,我們實現SetImagePath函數,它的功能是為按鈕背景圖片和父窗口背景圖片成員函數初始化,具體如下:
void CMyButton::SetImagePath(CString strImgPath, CString strParentImgPath)
{
????m_strImgPath = strImgPath;
????m_strImgParentPath = strParentImgPath;
}
第5步,我們實現InitMyButton函數,它的功能是調整按鈕在對話框上的位置,其中的參數代表該按鈕在父窗口的左上角X坐標,Y坐標,寬度,高度,最后一個參數是為PNG格式圖片準備的,如果是PNG帶透明色的圖片,需要對它進行特殊處理,具體定義如下:
bool CMyButton::InitMyButton(int nX, int nY, int nW, int nH, bool bIsPng)
{
????HRESULT hr = 0;
????if (m_strImgPath.IsEmpty())
????????return false;
????hr = m_imgButton.Load(m_strImgPath);
?
????if (FAILED(hr))
????????return false;
?
????if (bIsPng)
????{
????????if (m_imgButton.GetBPP() == 32)
????????{
????????????int i = 0;
????????????int j = 0;
????????????for (i = 0; i < m_imgButton.GetWidth(); i++)
????????????{
????????????????for (j = 0; j < m_imgButton.GetHeight(); j++)
????????????????{
????????????????????byte * pbyte = (byte *)m_imgButton.GetPixelAddress(i, j);
????????????????????pbyte[0] = pbyte[0] * pbyte[3] / 255;
????????????????????pbyte[1] = pbyte[1] * pbyte[3] / 255;
????????????????????pbyte[2] = pbyte[2] * pbyte[3] / 255;
????????????????}
????????????}
????????}
????}
?
????MoveWindow(nX,nY,nW,nH);
?
????return true;
}
其中MoveWindow函數是用來調整按鈕位置的函數,其中的參數分別代表其在父窗口的左上角X坐標,左上角Y坐標,寬度,高度。
第6步,我們實現DrawItem函數,它是美化Button的核心函數,當我們將Button設置為自繪制后,每次按鈕需要刷新,重新繪制的時候,MFC框架會調用它的DrawItem函數,在這個函數中,我們可以根據按鈕當前的狀態為其貼上相應的背景圖。當我們按鈕按鈕的時候,為其貼上被按下的背景圖;當我們的按鈕獲取焦點的時候,為其貼上獲取焦點的背景圖;當我們的按鈕沒有焦點,我們為其貼上默認的背景圖片,它們對應的位置前面已經說過。為了避免閃爍,我們采用雙緩沖的方式,具體代碼如下:
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
????if (!lpDrawItemStruct)
????????return;
????HDC hMemDC;
????HBITMAP bmpMem;
????HGDIOBJ hOldObj;
????bmpMem = CreateCompatibleBitmap(lpDrawItemStruct->hDC, lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left, lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top);
????if (!bmpMem)
????????return;
????hMemDC = CreateCompatibleDC(lpDrawItemStruct->hDC);
????if (!hMemDC)
????{
????????if (bmpMem)
????????{
????????????::DeleteObject(bmpMem);
????????????bmpMem = NULL;
????????}
????????return;
????}
?
????hOldObj = ::SelectObject(hMemDC, bmpMem);
?
????RECT rectTmp = { 0 };
?
????rectTmp = lpDrawItemStruct->rcItem;
?
????MapWindowPoints(GetParent(), &rectTmp);
?
????int nW = lpDrawItemStruct->rcItem.right - lpDrawItemStruct->rcItem.left;
?
????int nH = lpDrawItemStruct->rcItem.bottom - lpDrawItemStruct->rcItem.top;
?
????if (lpDrawItemStruct->itemState & ODS_SELECTED)
????{
????????//按鈕被選擇
????????m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW*2, 0, SRCCOPY);
????}
????else if (lpDrawItemStruct->itemState & ODS_FOCUS)
????{
???????????????//焦點狀態
??????????????m_imgButton.BitBlt(hMemDC, 0, 0, nW, nH, nW, 0, SRCCOPY);????????
????}
????else
????{
????????//默認狀態
????????CImage imgParent;
?
????????imgParent.Load(m_strImgParentPath);
?
????????imgParent.Draw(hMemDC, 0, 0, nW, nH, rectTmp.left, rectTmp.top, nW, nH);
?
????????m_imgButton.AlphaBlend(hMemDC, 0, 0, nW, nH, 0, 0, nW, nH);
?
????????imgParent.Destroy();
????????
????}
?
????::BitBlt(lpDrawItemStruct->hDC, 0, 0, nW, nH, hMemDC, 0, 0, SRCCOPY);
?
????SelectObject(hMemDC, hOldObj);
?
????if (bmpMem)
????{
????????::DeleteObject(bmpMem);
????????bmpMem = NULL;
????}
?
????if (hMemDC)
????{
????????::DeleteDC(hMemDC);
????????hMemDC = NULL;
????}
????return;
}
這里我們重點說一下默認狀態的背景圖,因為它是透明的,并且我們采用的是雙緩沖,所以,為了避免最終透明色變成黑色,我們先在內存DC上貼上按鈕在父窗口位置的背景圖,這樣可以解決透明色變成黑色的問題,如果你采用GDI+,就不用這么做,但是我們采用的是GDI。
第7步,用CMyButton替代對話框頭文件中的CButton。
第8步,在對話框的InitDialog中,對兩個按鈕進行初始化,具體如下:
m_btnMin.SetImagePath(_T("./res/btn_min.png"), _T("./res/Background.png"));
m_btnMin.InitMyButton(516, 8, 27, 21, true);
m_btnClose.SetImagePath(_T("./res/btn_close.png"),_T("./res/Background.png"));
m_btnClose.InitMyButton(545,8,27,21,true);
第9步,編譯程序,最終效果圖如下:
今天,我們已經為它添加了最小化,關閉按鈕,下次,我們為其添加編輯框!
原文:https://blog.csdn.net/yu__jia/article/details/83090442?
?
?
最近在為公司用MFC做產品界面。因為是小公司,所以也沒有現成的界面庫,必須自己一點一點寫。自己在網上收集了點資料,就寫了幾個類型的button類,以供以后使用。
目前為止,做了三種類型的按鈕,分別是:
1.一般情況使用的,比較常用的button類CNormalBtn;
2.特殊一點的,類似擁有菜單功能的button類CMenuBtn(和CNormal的區別是按鈕selected后的狀態不會隨著鼠標的離開而消失);
3.靜態按鈕,用來呈現log等圖片之類的button類CStatic,該類不會響應鼠標事件。
對于1,2種按鈕,用的圖片模式是:(png格式,一幅圖里有四副小圖,依次表示NoFoucs,Mousemove, buttondown, Disable四種狀態);
對于3類按鈕,用的圖片模式是:(png格式)
下面貼代碼:
基類代碼(BaseBtn.h)
#ifndef __BASEBTN_H__
#define __BASEBTN_H__
?
#include "stdafx.h"
#include <atlimage.h>
?
#if _MSC_VER > 1000
#pragma once
#endif
?
class CBaseBtn : public CButton
{
public:
?? ?CBaseBtn();
?? ?~CBaseBtn();
?
public:
?? ?virtual BOOL Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext = NULL);
?? ?virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
?? ?virtual void SetFont(CFont* pFont, BOOL bRedraw = TRUE);
?? ?virtual void SetWindowText(LPCTSTR lpszString);
?? ?
public:
?? ?void Init(UINT uImageID);
?? ?void SetBtnTextColor(COLORREF clr);
?? ??? ?
protected:
?? ?afx_msg BOOL OnEraseBkgnd(CDC* pDC);
?
?? ?DECLARE_MESSAGE_MAP()
?
protected:
?? ?int?? ??? ??? ?m_nCtrlState;
?
?? ?CImage?? ??? ?m_Image;
?? ?int?? ??? ??? ?m_nSrcWidth;
?? ?int?? ??? ??? ?m_nSrcHeight;
?
private:
?? ?CString?? ??? ?m_strBtnText;
?? ?CFont*?? ??? ?m_pFont;
?? ?COLORREF?? ?m_clr;
};
?
#endif
基類代碼(BaseBtn.cpp)
#include "stdafx.h"
#include "BaseBtn.h"
#include "Public.h"
?
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
?
CBaseBtn::CBaseBtn()
{
?? ?m_pFont = new CFont;
?? ?VERIFY(m_pFont->CreateFont(15, 0, 0, 0, FW_BOLD, FALSE, FALSE, 0, ANSI_CHARSET, OUT_DEFAULT_PRECIS,?
?? ??? ?CLIP_DEFAULT_PRECIS,DEFAULT_QUALITY, DEFAULT_PITCH | FF_SWISS, _T("Tahoma")));
?
?? ?m_strBtnText = L"";
?? ?m_clr = RGB(0, 0, 0);
}
?
CBaseBtn::~CBaseBtn()
{
?? ?if (!m_Image.IsNull())
?? ??? ?m_Image.Destroy();
?
?? ?if (m_pFont != NULL)
?? ?{
?? ??? ?m_pFont->DeleteObject();
?
?? ??? ?delete m_pFont;
?? ??? ?m_pFont = NULL;
?? ?}
}
?
BEGIN_MESSAGE_MAP(CBaseBtn, CButton)
?? ?ON_WM_ERASEBKGND()
END_MESSAGE_MAP()
?
void CBaseBtn::Init(UINT uImageID)
{
?? ?SetButtonStyle(BS_OWNERDRAW);
?
?? ?LoadPicture(m_Image, uImageID);
?? ?m_nSrcWidth = m_Image.GetWidth();
?? ?m_nSrcHeight = m_Image.GetHeight();
?
?? ?SetWindowPos(NULL, 0, 0, m_nSrcWidth/4, m_nSrcHeight, SWP_NOMOVE|SWP_NOACTIVATE);
?
?? ?if (IsWindowEnabled())
?? ??? ?m_nCtrlState = CTRL_NOFOCUS;
?? ?else
?? ??? ?m_nCtrlState = CTRL_DISABLE;
}
?
void CBaseBtn::SetFont(CFont* pFont, BOOL bRedraw)
{
?? ?m_pFont = pFont;
?
?? ?if(bRedraw)
?? ??? ?Invalidate();
}
?
void CBaseBtn::SetWindowText(LPCTSTR lpszString)
{
?? ?m_strBtnText = lpszString;
?? ?Invalidate();
}
?
void CBaseBtn::SetBtnTextColor(COLORREF clr)
{
?? ?m_clr = clr;
?? ?Invalidate();
}
?
BOOL CBaseBtn::Create(LPCTSTR lpszClassName, LPCTSTR lpszWindowName, DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID, CCreateContext* pContext)?
{
?? ?return CWnd::Create(lpszClassName, lpszWindowName, dwStyle, rect, pParentWnd, nID, pContext);
}
?
void CBaseBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)?
{
?? ?if (m_Image.IsNull())
?? ??? ?return ;
?
?? ?CRect buttonRect;
?? ?GetClientRect(buttonRect);
?
?? ?CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);?? ??? ?//按鈕控件DC
?
?? ?CDC dcMem;
?? ?dcMem.CreateCompatibleDC(pDC);
?
?? ?CBitmap memBitmap;
?? ?memBitmap.CreateCompatibleBitmap(pDC, buttonRect.Width(), buttonRect.Height());
?? ?dcMem.SelectObject(memBitmap);
?
?? ?dcMem.FillSolidRect(buttonRect, RGB(255,0,255));?? ?//設置畫布顏色
?
?? ?CRect rcSrc = CRect(0,0,0,0);
?? ?switch(m_nCtrlState)
?? ?{
?? ?case CTRL_NOFOCUS:
?? ??? ?{
?? ??? ??? ?rcSrc = CRect(0, 0, m_nSrcWidth/4, m_nSrcHeight);?? ??? ?
?? ??? ?}
?? ??? ?break;
?
?? ?case CTRL_FOCUS:
?? ??? ?{
?? ??? ??? ?rcSrc = CRect(m_nSrcWidth/4, 0, m_nSrcWidth/4 * 2, m_nSrcHeight);
?? ??? ?}
?? ??? ?break;
?? ?case CTRL_SELECTED:
?? ??? ?{
?? ??? ??? ?rcSrc = CRect(m_nSrcWidth/4 * 2, 0, m_nSrcWidth/4 * 3, m_nSrcHeight);
?? ??? ?}
?? ??? ?break;
?
?? ?case CTRL_DISABLE:
?? ??? ?{
?? ??? ??? ?rcSrc = CRect(m_nSrcWidth/4 * 3, 0, m_nSrcWidth, m_nSrcHeight);
?? ??? ?}
?? ??? ?break;
?
?? ?default:
?? ??? ?break;
?? ?}
?? ?m_Image.Draw(dcMem.m_hDC, buttonRect, rcSrc);
?
?? ?dcMem.SetBkMode(TRANSPARENT);
?? ?dcMem.SetTextColor(m_clr);
?? ?CFont* pOldFont = dcMem.SelectObject(m_pFont);
?? ?DrawText(dcMem.m_hDC, m_strBtnText, -1, buttonRect, DT_CENTER|DT_SINGLELINE|DT_VCENTER);
?? ?dcMem.SelectObject(pOldFont);
?
?? ?pDC->BitBlt(0, 0, buttonRect.Width(), buttonRect.Height(), &dcMem, 0, 0, SRCCOPY);
?? ?memBitmap.DeleteObject();
}
?
BOOL CBaseBtn::OnEraseBkgnd(CDC* pDC)
{
?? ?return TRUE;
}
第一類button(NormalBtn.h)
#ifndef __NORMALBTN_H__
#define __NORMALBTN_H__
?
#include "BaseBtn.h"
?
class CNormalBtn : public CBaseBtn
{
public:
?? ?CNormalBtn();
?? ?~CNormalBtn();
?
protected:
?? ?afx_msg void OnMouseMove(UINT nFlags, CPoint point);
?? ?afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
?? ?afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
?? ?afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM); ? ? ??
?? ?afx_msg LRESULT OnMouseHover(WPARAM, LPARAM);
?
?? ?DECLARE_MESSAGE_MAP()
?
private:
?? ?BOOL ? m_bTracking;?? ??? ??? ??? ??? ??? ?// 捕獲設置標記
?? ?
};
?
#endif
第一類button(NormalBtn. cpp)
#include "stdafx.h"
#include "NormalBtn.h"
#include "Public.h"
?
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
?
CNormalBtn::CNormalBtn()
?? ?:m_bTracking(FALSE)
{
?
}
?
CNormalBtn::~CNormalBtn()
{
?
}
?
BEGIN_MESSAGE_MAP(CNormalBtn, CBaseBtn)
?? ?ON_WM_MOUSEMOVE()
?? ?ON_WM_LBUTTONDOWN()
?? ?ON_WM_LBUTTONUP()
?? ?ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave) ? ? ??
?? ?ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
END_MESSAGE_MAP()
?
void CNormalBtn::OnMouseMove(UINT nFlags, CPoint point)?
{
?? ?if (!m_bTracking) ?
?? ?{ ??
?? ??? ?TRACKMOUSEEVENT tme; ?
?? ??? ?tme.cbSize = sizeof(tme); ?
?? ??? ?tme.hwndTrack = m_hWnd; ?
?? ??? ?tme.dwFlags = TME_LEAVE|TME_HOVER; ?
?? ??? ?tme.dwHoverTime = 1; ?
?? ??? ?m_bTracking = _TrackMouseEvent(&tme); ?
?? ?} ?
?
?? ?CBaseBtn::OnMouseMove(nFlags, point);
}
LRESULT CNormalBtn::OnMouseHover(WPARAM wParam,LPARAM lParam)
{
?? ?if (m_nCtrlState == CTRL_NOFOCUS)
?? ?{
?? ??? ?m_nCtrlState = CTRL_FOCUS;
?? ??? ?Invalidate();
?? ?}
?
?? ?m_bTracking = FALSE;
?? ?return 0;
}
?
LRESULT CNormalBtn::OnMouseLeave(WPARAM wParam,LPARAM ? lParam) ? ? ??
{ ??
?? ?if(m_nCtrlState != CTRL_NOFOCUS)
?? ?{
?? ??? ?m_nCtrlState = CTRL_NOFOCUS;
?? ??? ?Invalidate();
?? ?}
?
?? ?m_bTracking = FALSE;?
?? ?return 0; ? ? ??
} ? ? ??
?
void CNormalBtn::OnLButtonDown(UINT nFlags, CPoint point)?
{
?? ?if(m_nCtrlState == CTRL_FOCUS)
?? ?{
?? ??? ?m_nCtrlState = CTRL_SELECTED;
?? ??? ?Invalidate();
?? ?}
?
?? ?CBaseBtn::OnLButtonDown(nFlags, point);
}
?
void CNormalBtn::OnLButtonUp(UINT nFlags, CPoint point)
{
?? ?if(m_nCtrlState == CTRL_SELECTED)
?? ?{
?? ??? ?m_nCtrlState = CTRL_FOCUS;
?? ??? ?Invalidate();
?? ?}
?? ?CBaseBtn::OnLButtonUp(nFlags, point);
}
第二類按鈕(CMenu.h)
#ifndef __MENUBTN_H__
#define __MENUBTN_H__
?
#include "BaseBtn.h"
?
class CMenuBtn : public CBaseBtn
{
public:
?? ?CMenuBtn();
?? ?~CMenuBtn();
?
public:
?? ?BOOL GetMenuOn()?? ?{ return m_bMenuOn;?? ?}
?? ?void SetMenuOn(BOOL bMenuOn);
?
protected:
?? ?afx_msg void OnMouseMove(UINT nFlags, CPoint point);
?? ?afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
?? ?afx_msg LRESULT OnMouseLeave(WPARAM, LPARAM); ? ? ??
?? ?afx_msg LRESULT OnMouseHover(WPARAM, LPARAM);
?
?? ?DECLARE_MESSAGE_MAP()
?
private:
?? ?BOOL ? m_bTracking;?? ??? ??? ??? ??? ??? ?// 捕獲設置標記
?? ?BOOL ? m_bMenuOn;?? ??? ??? ??? ??? ??? ?// 該菜單按鈕是否被選中
?
};
?
#endif
第二類按鈕(CButton.cpp)
#include "stdafx.h"
#include "MenuBtn.h"
#include "Public.h"
?
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
?
CMenuBtn::CMenuBtn()
:m_bTracking(FALSE)
,m_bMenuOn(FALSE)
{
?
}
?
CMenuBtn::~CMenuBtn()
{
?
}
?
BEGIN_MESSAGE_MAP(CMenuBtn, CBaseBtn)
?? ?ON_WM_MOUSEMOVE()
?? ?ON_WM_LBUTTONDOWN()
?? ?ON_MESSAGE(WM_MOUSELEAVE,OnMouseLeave) ? ? ??
?? ?ON_MESSAGE(WM_MOUSEHOVER,OnMouseHover)
END_MESSAGE_MAP()
?
void CMenuBtn::OnMouseMove(UINT nFlags, CPoint point)?
{?? ??? ?
?? ?if (!m_bTracking) ?
?? ?{ ??
?? ??? ?TRACKMOUSEEVENT tme; ?
?? ??? ?tme.cbSize = sizeof(tme); ?
?? ??? ?tme.hwndTrack = m_hWnd; ?
?? ??? ?tme.dwFlags = TME_LEAVE|TME_HOVER; ?
?? ??? ?tme.dwHoverTime = 1; ?
?? ??? ?m_bTracking = _TrackMouseEvent(&tme); ?
?? ?} ?
?
?? ?CButton::OnMouseMove(nFlags, point);
}
?
void CMenuBtn::OnLButtonDown(UINT nFlags, CPoint point)?
{
?? ?if(m_nCtrlState != CTRL_SELECTED)
?? ?{
?? ??? ?m_nCtrlState = CTRL_SELECTED;
?? ??? ?m_bMenuOn = TRUE;
?? ??? ?Invalidate();
?? ?}
?
?? ?CButton::OnLButtonDown(nFlags, point);
}
?
LRESULT CMenuBtn::OnMouseLeave(WPARAM ? ? wParam,LPARAM ? lParam) ? ? ??
{ ??
?? ?if(m_bMenuOn)
?? ?{
?? ??? ?m_nCtrlState = CTRL_SELECTED;
?? ??? ?Invalidate();
?? ?}
?? ?else
?? ?{
?? ??? ?m_nCtrlState = CTRL_NOFOCUS;
?? ??? ?Invalidate();
?? ?}
?
?? ?m_bTracking = FALSE;?
?? ?return 0; ? ? ??
} ? ? ??
?
LRESULT CMenuBtn::OnMouseHover(WPARAM wParam,LPARAM lParam)
{
?? ?if (m_nCtrlState != CTRL_FOCUS)
?? ?{
?? ??? ?m_nCtrlState = CTRL_FOCUS;
?? ??? ?Invalidate();
?? ?}
?
?? ?m_bTracking = FALSE;
?? ?return 0;
}
?
void CMenuBtn::SetMenuOn(BOOL bMenuOn)
{
?? ?m_bMenuOn = bMenuOn;
?? ?Invalidate();
}
第三類按鈕(CStaticBtn.h)
#ifndef __STATICBTN_H__
#define __STATICBTN_H__
?
#include "BaseBtn.h"
?
class CStaticBtn : public CBaseBtn
{
public:
?? ?CStaticBtn();
?? ?~CStaticBtn();
?
public:
?? ?virtual void Init(UINT uImageID);
?? ?virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
};
?
?
#endif
第三類按鈕(CStaticBtn.cpp)
#include "stdafx.h"
#include "StaticBtn.h"
#include "Public.h"
?
CStaticBtn::CStaticBtn()
{
?
}
?
CStaticBtn::~CStaticBtn()
{
?
}
?
void CStaticBtn::Init(UINT uImageID)
{
?? ?SetButtonStyle(BS_OWNERDRAW);
?
?? ?LoadPicture(m_Image, uImageID);
?? ?m_nSrcWidth = m_Image.GetWidth();
?? ?m_nSrcHeight = m_Image.GetHeight();
?
?? ?SetWindowPos(NULL, 0, 0, m_nSrcWidth, m_nSrcHeight, SWP_NOMOVE|SWP_NOACTIVATE);
}
?
void CStaticBtn::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
?? ?if (m_Image.IsNull())
?? ??? ?return;
?
?? ?CRect rcBtutton;
?? ?GetClientRect(rcBtutton);
?
?? ?CDC* pDC = CDC::FromHandle(lpDrawItemStruct->hDC);
?
?? ?CRect rcSrc = CRect(0, 0, m_nSrcWidth, m_nSrcHeight);
?? ?m_Image.Draw(pDC->m_hDC, rcBtutton, rcSrc);
}
使用方法:
CNoraml m_NorBtn;
m_NorBtn.Init(UNIT);
因為NormalBtn和MenuBtn需要相應鼠標事件,有圖片切換,為了更好的圖片切換效果使用雙緩沖繪圖。雙緩沖繪圖需要先創建一張畫布(CBaseBtn::DrawItem()函數)
?? ?CBitmap memBitmap;
?? ?memBitmap.CreateCompatibleBitmap(pDC, buttonRect.Width(), buttonRect.Height());
?? ?dcMem.SelectObject(memBitmap);
?? ?dcMem.FillSolidRect(buttonRect, RGB(255,0,255));?? ?//設置畫布顏色
所以雖然用了雖然PNG圖片有透明屬性,但是畫布無法設置透明屬性,最后的結果是雖然PNG圖片背景透明了,因為畫布的存在,無法做出一個不規程的按鈕出來。
而StaticBtn使用的是單緩沖,沒有畫布的存在,利用PNG圖片的透明屬性,可以做出一個不規則的按鈕。但是單緩沖繪圖對于圖片的切換效果不好,所以只用來做一個不響應鼠標消息的靜態按鈕。未來有空我將會寫《MFC 之 CButton 控件重繪(GDI+篇)》利用GDI+繪圖來解決這個問題。
完整的項目工程下載地址:http://download.csdn.net/detail/yuzhenxiong0823/7167827
原文:https://blog.csdn.net/yuzhenxiong0823/article/details/23278763?
?
總結
以上是生活随笔為你收集整理的MFC 之 重绘按键Cbutton的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: DirectShow组件原理分析及应用
- 下一篇: VC的MFC中重绘函数的使用总结(整理)