I quickly threw together a derived CButton
class to make a round button using ownerdraw, but it seems the DrawIconEx
function is drawing outside the region because the drawn button is square. I even tried making a copy of the region and specifically selecting it. The window itself seems to be round based on the mouse events don't enter that button when inside the corners. Does DrawIconEx
not support clipping regions or is there something else going on?
My test icons were just added to the project using Add Resource / Icon. I then just named them using what Visual Studio gave me.
Here's the header:
class CMyButton : public CButton
{
protected:
HRGN m_hRegion=NULL;
HICON m_hIconNormal=NULL;
HICON m_hIconSelected=NULL;
LPCTSTR m_szResIDIconNormal;
LPCTSTR m_szResIDIconSelected;
public:
// Constructor / Destructor
CMyButton(LPCTSTR idnormal, LPCTSTR idselected);
virtual ~CMyButton();
// Overrides
//{{AFX_VIRTUAL(CMyButton)
public:
virtual void DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct);
protected:
virtual void PreSubclassWindow();
//}}AFX_VIRTUAL
// Implementation
public:
// Generated message map functions
DECLARE_MESSAGE_MAP()
afx_msg int OnCreate(LPCREATESTRUCT lpCreateStruct);
};
Here's the Source:
/////////////////////////////////////////////////////////////////////////////
// CMyButton
CMyButton::CMyButton(LPCTSTR idnormal, LPCTSTR idselected)
{
m_szResIDIconNormal=idnormal;
m_szResIDIconSelected=idselected;
}
CMyButton::~CMyButton()
{
if (m_hIconNormal)
DestroyIcon(m_hIconNormal);
if (m_hIconSelected)
DestroyIcon(m_hIconSelected);
m_hIconNormal=m_hIconSelected=NULL;
}
BEGIN_MESSAGE_MAP(CMyButton, CButton)
//{{AFX_MSG_MAP(CMyButton)
//}}AFX_MSG_MAP
ON_WM_CREATE()
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CMyButton message handlers
void CMyButton::PreSubclassWindow()
{
ModifyStyle(0,BS_OWNERDRAW);
CButton::PreSubclassWindow();
}
void CMyButton::DrawItem(LPDRAWITEMSTRUCT lpdrawitemstruct)
{
// draw the icon into the device context:
CRect rc;
GetWindowRect(&rc);
int result=SelectClipRgn(lpdrawitemstruct->hDC, m_hRegion);
CDebugPrint::DebugPrint(_T("SelectClipRgn result:%i\n"), result); // output is: 3
if (lpdrawitemstruct->itemState & ODS_SELECTED) {
DrawIconEx(lpdrawitemstruct->hDC, 0, 0, m_hIconSelected, rc.Width(), rc.Height(), 0, NULL, DI_NORMAL);
}
else {
DrawIconEx(lpdrawitemstruct->hDC, 0, 0, m_hIconNormal, rc.Width(), rc.Height(), 0, NULL, DI_NORMAL);
}
}
int CMyButton::OnCreate(LPCREATESTRUCT lpCreateStruct)
{
if (CButton::OnCreate(lpCreateStruct) == -1)
return -1;
// determine size
CRect winrect;
GetWindowRect(&winrect);
// create region of the given size
HRGN hrgn=CreateEllipticRgn(0, 0, winrect.Width(), winrect.Height());
m_hRegion=CreateEllipticRgn(0, 0, 0, 0);
int result=CombineRgn(m_hRegion, hrgn, NULL, RGN_COPY);
CDebugPrint::DebugPrint(_T("CombineRgn result:%i\n"), result); // output is 3
SetWindowRgn(hrgn, FALSE);
// load icons matching size
int size=winrect.Width();
HINSTANCE hinstance=GetModuleHandle(NULL);
m_hIconNormal=(HICON) LoadImage(hinstance, m_szResIDIconNormal, IMAGE_ICON, size, size, 0);
m_hIconSelected=(HICON) LoadImage(hinstance, m_szResIDIconSelected, IMAGE_ICON, size, size, 0);
return 0;
}
Here's how I created them in the CDialogEx
:
// create 32x32 button (rcbut is where it goes, it's 32x32)
CMyButton *mybutton=new CMyButton(MAKEINTRESOURCE(IDI_ICONTEST), MAKEINTRESOURCE(IDI_ICONTEST));
mybutton->Create(_T("Whatever"), BS_NOTIFY|WS_CHILD|WS_VISIBLE|WS_TABSTOP|BS_PUSHBUTTON, rcbut, this, IDC_MYBUTTON);