RgnButton.h
#pragma once
#include "afxwin.h"
class CRgnButton :
public CButton
{
DECLARE_DYNAMIC(CRgnButton)
public:
CRgnButton();
~CRgnButton();
virtual void SetImage(Image* img);
virtual void SetImageHover(Image* img);
virtual void Create(CWnd* pParentWnd, UINT nID);
private:
// 设置窗体区域
void SetRgn(CRgn *region);
// 读取图片的非透明区生成区域
Region* CreateRegion(Image* img);
Image* m_image;
Point m_imgOffset;
HRGN rgn, trgn;
Image* m_imageHover;
bool m_isHover;
bool m_isHoverShowing;
protected:
DECLARE_MESSAGE_MAP()
virtual void PreSubclassWindow();
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
afx_msg void OnLButtonDown(UINT nFlags, CPoint point);
afx_msg void OnLButtonUp(UINT nFlags, CPoint point);
afx_msg void OnMouseLeave();
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg void OnMouseHover(UINT nFlags, CPoint point);
};
RgnButton.cpp
#include "stdafx.h"
#include "RgnButton.h"
IMPLEMENT_DYNAMIC(CRgnButton, CButton)
CRgnButton::CRgnButton()
{
m_isHover = false;
m_isHoverShowing = false;
this->m_image = NULL;
this->m_imageHover = NULL;
this->m_imgOffset = Point(0, 0);
}
void CRgnButton::SetImage(Image* img)
{
this->m_image = img;
Region* rgn = CreateRegion(img);
Graphics g(GetWindowDC()->m_hDC);
HRGN hrgn = rgn->GetHRGN(&g);
CRgn * crgn = CRgn::FromHandle(hrgn);
SetRgn(crgn);
delete rgn;
}
void CRgnButton::SetImageHover(Image* img)
{
this->m_imageHover = img;
/*
Region* rgn = CreateRegion(img);
Graphics g(GetWindowDC()->m_hDC);
HRGN hrgn = rgn->GetHRGN(&g);
CRgn * crgn = CRgn::FromHandle(hrgn);
SetRgn(crgn);
delete rgn;
*/
}
CRgnButton::~CRgnButton()
{
if (m_image)
{
delete m_image;
}
}
void CRgnButton::Create(CWnd*pParentWnd, UINT nID){
CWnd* target = pParentWnd->GetDlgItem(nID);
CRect rc;
target->GetWindowRect(&rc);
pParentWnd->ScreenToClient(&rc);
__super::Create(NULL, WS_CHILD | WS_VISIBLE | WS_TABSTOP | BS_PUSHBUTTON | BS_OWNERDRAW, CRect(rc.left,
rc.top,
m_image->GetWidth() + rc.left,
m_image->GetHeight() + rc.top),
pParentWnd,
nID);
}
Region* CRgnButton::CreateRegion(Image* img){
Bitmap* bmp = new Bitmap(img->GetWidth(), img->GetHeight());
Graphics* g = Graphics::FromImage(bmp);
g->DrawImage(img, 0, 0, img->GetWidth(), img->GetHeight());
GraphicsPath gp;
for (int i = 0; i < (int)bmp->GetWidth(); i++)
{
for (int j = 0; j < (int)bmp->GetHeight(); j++)
{
Color cl;
bmp->GetPixel(i, j, &cl);
if (cl.GetA() != 0)
{
gp.AddRectangle(Rect(i, j, 1, 1));
}
}
}
delete g;
delete bmp;
return new Region(&gp);
}
void CRgnButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{
SetWindowRgn(rgn, true);
if (m_isHover&&m_imageHover){
m_isHoverShowing = true;
Graphics g(lpDrawItemStruct->hDC);
g.SetClip(trgn, CombineModeReplace);
switch (lpDrawItemStruct->itemAction)
{
case ODA_SELECT:
case ODA_DRAWENTIRE:
case ODA_FOCUS:
{
g.DrawImage(m_imageHover, RectF((REAL)m_imgOffset.X, (REAL)m_imgOffset.Y, (REAL)m_image->GetWidth(), (REAL)m_image->GetHeight()));
}
break;
}
}
else if (m_image)
{
Graphics g(lpDrawItemStruct->hDC);
g.SetClip(trgn, CombineModeReplace);
switch (lpDrawItemStruct->itemAction)
{
case ODA_SELECT:
case ODA_DRAWENTIRE:
case ODA_FOCUS:
{
g.DrawImage(m_image, RectF((REAL)m_imgOffset.X, (REAL)m_imgOffset.Y, (REAL)m_image->GetWidth(), (REAL)m_image->GetHeight()));
}
break;
}
}
}
BEGIN_MESSAGE_MAP(CRgnButton, CButton)
ON_WM_LBUTTONDOWN()
ON_WM_LBUTTONUP()
ON_WM_MOUSELEAVE()
ON_WM_MOUSEMOVE()
ON_WM_MOUSEHOVER()
END_MESSAGE_MAP()
void CRgnButton::SetRgn(CRgn *region){
rgn = ::CreateRectRgn(0, 0, 0, 0);
CombineRgn(rgn, region->operator HRGN(), NULL, RGN_COPY);
trgn = ::CreateRectRgn(0, 0, 0, 0);
CombineRgn(trgn, region->operator HRGN(), NULL, RGN_COPY);
}
void CRgnButton::PreSubclassWindow(){
ModifyStyle(0, BS_OWNERDRAW | WS_CLIPSIBLINGS);
CButton::PreSubclassWindow();
}
void CRgnButton::OnLButtonDown(UINT nFlags, CPoint point)
{
m_imgOffset.X = 1;
m_imgOffset.Y = 1;
CButton::OnLButtonDown(nFlags, point);
}
void CRgnButton::OnLButtonUp(UINT nFlags, CPoint point)
{
m_imgOffset.X = 0;
m_imgOffset.Y = 0;
CButton::OnLButtonUp(nFlags, point);
}
void CRgnButton::OnMouseLeave()
{
m_isHover = false;
m_imgOffset.X = 0;
m_imgOffset.Y = 0;
m_isHoverShowing = false;
InvalidateRect(NULL, FALSE);
CButton::OnMouseLeave();
}
void CRgnButton::OnMouseMove(UINT nFlags, CPoint point)
{
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(TRACKMOUSEEVENT);
tme.dwFlags = TME_LEAVE | TME_HOVER;//要触发的消息
tme.hwndTrack = this->m_hWnd;
tme.dwHoverTime = 10;// 若不设此参数,则无法触发mouseHover
::_TrackMouseEvent(&tme); //MOUSELEAVE|MOUSEHOVER消息由此函数触发
CButton::OnMouseMove(nFlags, point);
}
void CRgnButton::OnMouseHover(UINT nFlags, CPoint point)
{
m_isHover = true;
m_imgOffset.X = 0;
m_imgOffset.Y = 0;
if (!m_isHoverShowing)InvalidateRect(NULL);
CButton::OnMouseHover(nFlags, point);
}