0

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);
user3161924
  • 1,849
  • 18
  • 33
  • Try replacing the `DrawIconEx()` with a `FillRect()` to see whether it's the region itself or something specific to the DrawIconEx function. – Jonathan Potter Jul 28 '20 at 01:09
  • That did show something. It shows the fill area round, but grey on the corners where it's square. So it seems like the area outside the region but part of the Window RECT gets something drawn in it. I seem to recall something like this due to buttons when trying to make them transparent. It's over the top of an image that covers the dialog area so maybe needs something to make that outside area transparent?? – user3161924 Jul 28 '20 at 01:20
  • I'm wondering how the call to `SetWindowRgn` is interacting with your drawing using a region. Maybe comment out the `SetWindowRgn` call for the moment, and then work on getting the drawing correct. – Jonathan Potter Jul 28 '20 at 01:22
  • I added `OnEraseBkgnd(CDC* pDC)` handler to just return `TRUE`, now it's round. – user3161924 Jul 28 '20 at 01:42

0 Answers0