之前我有写过两篇MFC 下按钮的重绘,今天我给大家提供一种自绘方法
#pragma once
#include <string>
// ClrButton
#define WM_LRBTNCLICK (WM_USER + 532)
class ClrButton : public CWnd
{
DECLARE_DYNAMIC(ClrButton)
public:
ClrButton();
virtual ~ClrButton();
public:
enum
{
State_Normal,
State_Focus,
State_Press,
State_Disable
};
Image* GetPngStream(UINT uiID);
BOOL SetImage(UINT uiImg);
BOOL SetFourImage(UINT uiNormalImg, UINT uiFocusImg, UINT uiPressImg, UINT uiDisableImg);
BOOL SetCaption( const wchar_t *szText);
void SetCheck( BOOL bCheck);
void SetFourPicMode(){m_bFourPicMode = TRUE;}
BOOL GetCheck();
protected:
BOOL DrawItem( CDC *pDC);
private:
BOOL m_bFourPicMode;
BOOL m_bCheck;
DWORD m_dwState;
BOOL m_bMouseLeave;
BOOL m_bDowned;
BOOL m_bFocus;
UINT m_uiImg;
UINT m_uiNormalImg;
UINT m_uiFocusImg;
UINT m_uiPressImg;
UINT m_uiDisableImg;
std::wstring m_strText;
protected:
DECLARE_MESSAGE_MAP()
public:
virtual BOOL Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID);
afx_msg void OnPaint();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseLeave(WPARAM wParam, LPARAM lParam);
afx_msg void OnSetFocus(CWnd* pOldWnd);
afx_msg void OnKillFocus(CWnd* pNewWnd);
};
实现
// lrButton.cpp : 实现文件
//
#include "stdafx.h"
#include "lrButton.h"
#pragma comment( lib, "UxTheme.lib")
// ClrButton
IMPLEMENT_DYNAMIC(ClrButton, CWnd)
ClrButton::ClrButton()
{
m_dwState = State_Normal;
m_bCheck = FALSE;
m_bMouseLeave = TRUE;
m_bDowned = FALSE;
m_bFocus = FALSE;
m_bFourPicMode = FALSE;
m_uiImg = 0;
m_uiNormalImg = 0;
m_uiFocusImg = 0;
m_uiPressImg = 0;
m_uiDisableImg = 0;
}
ClrButton::~ClrButton()
{
}
BEGIN_MESSAGE_MAP(ClrButton, CWnd)
ON_WM_PAINT()
ON_WM_MOUSEMOVE()
ON_MESSAGE( WM_MOUSELEAVE, OnMouseLeave)
ON_WM_LBUTTONUP()
ON_WM_LBUTTONDOWN()
ON_WM_SETFOCUS()
ON_WM_KILLFOCUS()
END_MESSAGE_MAP()
// ClrButton 消息处理程序
BOOL ClrButton::Create( DWORD dwStyle, const RECT& rect, CWnd* pParentWnd, UINT nID)
{
return CreateEx(
0,
AfxRegisterWndClass(0),
0,
dwStyle,
rect,
pParentWnd,
nID);
}
Image* ClrButton::GetPngStream(UINT uiID)
{
HINSTANCE hInst = AfxGetResourceHandle();
HRSRC hRsrc = ::FindResource (hInst,MAKEINTRESOURCE(uiID),_T("PNG")); // type
if (!hRsrc)
return NULL;
// load resource into memory
DWORD len = SizeofResource(hInst, hRsrc);
BYTE* lpRsrc = (BYTE*)LoadResource(hInst, hRsrc);
if (!lpRsrc)
return NULL;
// Allocate global memory on which to create stream
HGLOBAL m_hMem = GlobalAlloc(GMEM_FIXED, len);
BYTE* pmem = (BYTE*)GlobalLock(m_hMem);
memcpy(pmem,lpRsrc,len);
IStream* pstm;
CreateStreamOnHGlobal(m_hMem,FALSE,&pstm);
// load from stream这是关键一句,通过FromStream返回以各Image*,然后在Graphic的DrawImage地方调用就行了!
Image* pImg = Gdiplus::Image::FromStream(pstm);
// free/release stuff
GlobalUnlock(m_hMem);
pstm->Release();
FreeResource(lpRsrc);
return pImg;
}
BOOL ClrButton::DrawItem( CDC *pDC )
{
if((m_uiImg == 0) && (m_uiNormalImg == 0) && (m_uiFocusImg == 0) && (m_uiPressImg == 0) && (m_uiDisableImg == 0))
return TRUE;
HDC hdc = pDC->GetSafeHdc();
HDC hMemdc = CreateCompatibleDC( hdc);
CRect rt;
GetClientRect( &rt);
BYTE* pBits = NULL;
BITMAPINFOHEADER bmih = { sizeof (BITMAPINFOHEADER) };
bmih.biWidth = rt.Width();
bmih.biHeight = rt.Height();
bmih.biPlanes = 1;
bmih.biBitCount = 32;
bmih.biCompression = BI_RGB;
bmih.biSizeImage = 0;
bmih.biXPelsPerMeter = 0;
bmih.biYPelsPerMeter = 0;
bmih.biClrUsed = 0;
bmih.biClrImportant = 0;
HBITMAP hMembmp = CreateDIBSection(NULL, (BITMAPINFO *)&bmih, DIB_RGB_COLORS, (VOID**)&pBits, NULL, 0);
HBITMAP hOldbmp = (HBITMAP)SelectObject( hMemdc, hMembmp);
DrawThemeParentBackground( m_hWnd,hMemdc, &rt);
Graphics graphics( hMemdc);
Image* img = NULL;
if(m_bFourPicMode)
{
if(m_dwState == State_Normal)
img = GetPngStream(m_uiNormalImg);
else if(m_dwState == State_Focus)
img = GetPngStream(m_uiFocusImg);
else if(m_dwState == State_Press)
img = GetPngStream(m_uiPressImg);
else if(m_dwState == State_Disable)
img = GetPngStream(m_uiDisableImg);
graphics.DrawImage(img,RectF( 0, 0, rt.Width(), rt.Height()), 0, 0, img->GetWidth(), img->GetHeight(), UnitPixel);
}
else
{
img = GetPngStream(m_uiImg);
graphics.DrawImage(img,RectF( 0, 0, rt.Width(), rt.Height()), m_dwState * img->GetWidth()/4, 0, img->GetWidth()/4, img->GetHeight(), UnitPixel);
}
//draw text
FontFamily fontfamily(L"宋体");
Gdiplus::Font font( &fontfamily, 9, FontStyleRegular, UnitPoint);
StringFormat stringformat;
stringformat.SetAlignment( StringAlignmentCenter);
stringformat.SetLineAlignment(StringAlignmentCenter);
SolidBrush brush(Color(254,159,239,255));
RectF reF(0, 0, rt.Width(), rt.Height());
if ( !m_strText.empty() )
graphics.DrawString( m_strText.c_str(), -1, &font, reF, &stringformat,&brush);
BitBlt( hdc,0,0,rt.Width(), rt.Height(), hMemdc, 0,0,SRCCOPY);
graphics.ReleaseHDC( hMemdc);
SelectObject( hMemdc, hOldbmp);
DeleteDC( hMemdc);
DeleteObject( hMembmp);
if ( GetFocus() == (CWnd *)this
&& (GetWindowLong( m_hWnd, GWL_STYLE) &WS_TABSTOP ) )
{
CRect rtFocus;
GetClientRect( &rtFocus);
rtFocus.DeflateRect( 3,3,3,3);
DrawFocusRect( pDC->GetSafeHdc(), &rtFocus );
}
return TRUE;
}
BOOL ClrButton::SetImage(UINT uiImg)
{
m_uiImg = uiImg;
Invalidate( FALSE);
return TRUE;
}
BOOL ClrButton::SetFourImage(UINT uiNormalImg, UINT uiFocusImg, UINT uiPressImg, UINT uiDisableImg)
{
m_uiNormalImg = uiNormalImg;
m_uiFocusImg = uiFocusImg;
m_uiPressImg = uiPressImg;
m_uiDisableImg = uiDisableImg;
Invalidate(FALSE);
return TRUE;
}
void ClrButton::OnPaint()
{
CPaintDC dc(this); // device context for painting
DrawItem( &dc);
}
void ClrButton::OnMouseMove(UINT nFlags, CPoint point)
{
if ( m_bMouseLeave )
{
TRACKMOUSEEVENT evt = { 0 };
evt.cbSize = sizeof(evt);
evt.dwFlags = TME_LEAVE;
evt.hwndTrack = m_hWnd;
TrackMouseEvent( &evt);
m_bMouseLeave = FALSE;
m_dwState = State_Focus;
Invalidate(FALSE);
}
CWnd::OnMouseMove(nFlags, point);
}
void ClrButton::OnLButtonUp(UINT nFlags, CPoint point)
{
if ( m_bDowned )
{
m_dwState = State_Focus;
Invalidate(FALSE );
GetParent()->PostMessage( WM_LRBTNCLICK, GetDlgCtrlID(), 0);
m_bDowned = FALSE;
}
CWnd::OnLButtonUp(nFlags, point);
}
void ClrButton::OnLButtonDown(UINT nFlags, CPoint point)
{
m_bDowned = TRUE;
m_dwState = State_Press;
if ( (GetWindowLong( m_hWnd, GWL_STYLE) &WS_TABSTOP ) )
SetFocus();
Invalidate(FALSE);
CWnd::OnLButtonDown(nFlags, point);
}
BOOL ClrButton::SetCaption( const wchar_t *szText )
{
m_strText = szText;
Invalidate(FALSE);
return TRUE;
}
void ClrButton::SetCheck( BOOL bCheck )
{
m_bCheck = bCheck;
Invalidate(FALSE);
}
BOOL ClrButton::GetCheck()
{
return m_bCheck;
}
LRESULT ClrButton::OnMouseLeave( WPARAM wParam, LPARAM lParam )
{
m_bMouseLeave = TRUE;
m_dwState = State_Normal;
Invalidate(FALSE);
return 0;
}
void ClrButton::OnSetFocus(CWnd* pOldWnd)
{
CWnd::OnSetFocus(pOldWnd);
m_bFocus = TRUE;
Invalidate(FALSE);
}
void ClrButton::OnKillFocus(CWnd* pNewWnd)
{
CWnd::OnKillFocus(pNewWnd);
m_bFocus = FALSE;
Invalidate(FALSE);
}
使用示例,最小化和关闭按钮
///定义
ClrButton* m_plrBtn;
///声明
if(m_plrBtn == NULL)
m_plrBtn = new ClrButton[2];
CRect rtClose(m_rcClient.right - 45, 0,m_rcClient.right, 26);
m_plrBtn[0].Create( WS_CHILD|WS_VISIBLE, rtClose, this, IDC_BTNCLOSE);
m_plrBtn[0].ShowWindow(SW_SHOW);
m_plrBtn[0].UpdateWindow();
m_plrBtn[0].SetImage(IDD_PNG_CLOSE);
CRect rtMin( rtClose.left-31, 0, rtClose.left, 26);
m_plrBtn[1].Create( WS_CHILD|WS_VISIBLE, rtMin, this, IDC_BTNMIN);
m_plrBtn[1].ShowWindow(SW_SHOW);
m_plrBtn[1].UpdateWindow();
m_plrBtn[1].SetImage(IDD_PNG_MIN);
有空我会把添加一些注释,方便大家阅读。欢迎评论、指正。