SetWindowRgn with antialiasing

203 Views Asked by At

Does SetWindowRgn support anti-aliasing? And if so, how to set it up?

1

There are 1 best solutions below

2
aitolate On

I guess the region itself can't be set so that the edges of the region are AntiAliased, but there can be a way to work with a custom region and AntiAliasing.

I was struggling with SetWindowRgn and a custom styled CButton (BS_OWNERDRAW enabled) with rounded corners. I wanted to set a rounded rectangle region and render a rounded rectangle button with AntiAliasing enabled. When I enabled AntiAliasing, the edges of my button would interfere with the color which was used in the previous rendering. This was a problem when the button changes color due to a state change like being hovered, disabled or enabled. I noticed that if I forward OnEraseBkgn -call to base class, then the rendering would work correctly in my Region with AntiAliasing enabled.

I had to create an account so that I could share my experiences.

This is a snippet for setting the custom region which I'm using:

CRect rectClient;
CRgn rgnRounded;

this->GetClientRect( rectClient );

rgnRounded.CreateRoundRectRgn( rectClient.left, rectClient.top,
    rectClient.right, rectClient.bottom, 24, 24 );
int result = this->SetWindowRgn( rgnRounded, TRUE );

Then my EraseBkgnd handler:

/*!
The MFC framework calls this member function when the CWnd object 
background needs erasing (for example, when resized).
*/
BOOL CCustomButton::OnEraseBkgnd(
    _In_ CDC* pDC  //!< Specifies the device-context object.
)
{
    BOOL bRetVal = FALSE;

    // Call base class.
    bRetVal = __super::OnEraseBkgnd( pDC );

    return bRetVal;
}

Then I have my rendering:

/*!
The MFC framework calls this member function for the owner of an 
owner-drawn button control.
*/
void CCustomButton::DrawItem(
    IN LPDRAWITEMSTRUCT lpDrawItemStruct  //!< Specifies a long pointer to a DRAWITEMSTRUCT data structure that contains information about the item to be drawn and the type of drawing required.
)
{
    // Get handle to drawing context.
    HDC hDC = lpDrawItemStruct->hDC;

    // Use Gdiplus rendering for rounded shape.
    Gdiplus::Graphics gr( hDC );

    // Get the client rectangle.
    CRect rectClient;
    GetClientRect( OUT &rectClient );  // void
    
    // Draw and fill rounded rectangle.
    Gdiplus::Rect gdiplusrectClient( 0, 0,
        rectClient.right - rectClient.left, rectClient.bottom - rectClient.top );
    Gdiplus::GraphicsPath pathRoundedRectangle;
    GetRoundRectPath( gdiplusrectClient, 24, &pathRoundedRectangle );  // My custom function.
    Gdiplus::Color colorBk;
    colorBk.SetFromCOLORREF( RGB( 255, 0, 0 ) );
    Gdiplus::SolidBrush brushBk( colorBk );
    gr.SetSmoothingMode( Gdiplus::SmoothingModeHighQuality );
    gr.FillPath( &brushBk, &pathRoundedRectangle );

}

It seems that passing the OnEraseBkgnd to a base class such as one derived from a CButton allows for clearing the background so the client area's drawing context contains what the parent would render there. This seems likely to happen because a custom region was set for this window.

EDIT: Welp, there is still an issue when the window containing the control is resized and the controls move, there are some residuals visible. I think there is a way to fix that, but I was not allocated time to investigate it further.