MFC Custom Button control

2.3k views Asked by At

I have created a custom button in mfc(VS 2013)DLL. It worked Fine. I have created a test dialog exe to test the dll. Then I added some code to simulate hover effect. Now when I run the Dialog exe, the button appears as wanted but when move the cursor on top of the button, the gradient changes but it throws an Debug Assertion.

void CBootstrapButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
{

    dc = CDC::FromHandle(lpDrawItemStruct->hDC);//Get device context object

    m_bIsFocused = (lpDrawItemStruct->itemState & ODS_FOCUS);
    m_bIsDisabled = (lpDrawItemStruct->itemState & ODS_DISABLED);
    m_bIsPressed = (lpDrawItemStruct->itemState & ODS_SELECTED);

    //Preparing the Region to Draw

    CRect btnRect = lpDrawItemStruct->rcItem;
    int iCX = lpDrawItemStruct->rcItem.right;
    int iCY = lpDrawItemStruct->rcItem.bottom;

    CRgn Rgn1;//<-this is where I am getting assertion error
    Rgn1.CreateRoundRectRgn(0, 0, lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom, 10, 10);
    dc->SelectClipRgn(&Rgn1);

    MemDC.CreateCompatibleDC(dc);
    pDC = &MemDC;

    Bmp.CreateCompatibleBitmap(dc, iCX, iCY);
    OldBitmap = MemDC.SelectObject(&Bmp);

    border = RGB(219, 219, 219);//Button Border color

    /******* Some Color Logic*******/

    //Applying Border
    pDC->RoundRect(0, 0, lpDrawItemStruct->rcItem.right, lpDrawItemStruct->rcItem.bottom, 10, 10);
    pDC->FillSolidRect(&lpDrawItemStruct->rcItem, border);

    if (m_bIsFocused)
    {
        pDC->DrawFocusRect(&lpDrawItemStruct->rcItem);
    }

    //Applying Gradients
    CRgn Rgn2;
    Rgn2.CreateRoundRectRgn(1, 1, lpDrawItemStruct->rcItem.right - 1, lpDrawItemStruct->rcItem.bottom - 1, 10, 10);
    pDC->SelectClipRgn(&Rgn2);

    RECT rect = lpDrawItemStruct->rcItem;

    for (int i = 0; i<rect.bottom; i++)  
    {
        int r, g, b;
        r = r1 + (i * (r2 - r1) / rect.bottom);
        g = g1 + (i * (g2 - g1) / rect.bottom);
        b = b1 + (i * (b2 - b1) / rect.bottom);
        pDC->FillSolidRect(0, i, rect.right, 1, RGB(r, g, b));
    }

    //Start Drawing Text
    CString strText;
    GetWindowText(strText);
    int iOldMode = pDC->SetBkMode(TRANSPARENT);

    COLORREF crOldColor;

    //Setting Text Color
    if (btnStyle==BTN_DEFAULT)
    {
        crOldColor = pDC->SetTextColor(RGB(0, 0, 0));
    }
    else
    {
        crOldColor = pDC->SetTextColor(RGB(255, 255, 255));
    }


    //Setting Font for Text (Default Font Name=Open Sans,Default Font Size=24)
    //TODO Font Size according to Button Size.
    CFont font;
    font.CreateFont(
        24,                        // nHeight//Font Size
        0,                         // nWidth
        0,                         // nEscapement
        0,                         // nOrientation
        FW_NORMAL,                 // nWeight
        FALSE,                     // bItalic
        FALSE,                     // bUnderline
        0,                         // cStrikeOut
        ANSI_CHARSET,              // nCharSet
        OUT_DEFAULT_PRECIS,        // nOutPrecision
        CLIP_DEFAULT_PRECIS,       // nClipPrecision
        DEFAULT_QUALITY,           // nQuality
        DEFAULT_PITCH | FF_SWISS,  // nPitchAndFamily
        _T("Open Sans"));

    CFont* def_font = pDC->SelectObject(&font);

    //Draw Text
    pDC->DrawText(strText, &lpDrawItemStruct->rcItem, DT_CENTER | DT_VCENTER | DT_SINGLELINE);
    dc->BitBlt(0, 0, iCX, iCY, pDC, 0, 0, SRCCOPY);

    pDC->SetTextColor(crOldColor);
    pDC->SetBkMode(iOldMode);
    pDC->SelectObject(OldBitmap);
    pDC->SelectObject(def_font);
    //End Drawing Text

    //Cleaning up
    pDC->DeleteDC();
    dc->SelectClipRgn(NULL);
    dc->Detach();
}

Code for hover Effect

void CBootstrapButton::OnMouseMove(UINT nFlags, CPoint point)
{
    CWnd* wndUnderMouse = NULL;
    CWnd* wndActive = this;
    TRACKMOUSEEVENT csTME;

    CButton::OnMouseMove(nFlags, point);

    ClientToScreen(&point);
    wndUnderMouse = WindowFromPoint(point);

    if (nFlags & MK_LBUTTON && m_bMouseOnButton == FALSE) return;

    wndActive = GetActiveWindow();

    if (wndUnderMouse && wndUnderMouse->m_hWnd == m_hWnd && wndActive)
    {
        if (!m_bMouseOnButton)
        {
            m_bMouseOnButton = TRUE;

            Invalidate();

            csTME.cbSize = sizeof(csTME);
            csTME.dwFlags = TME_LEAVE;
            csTME.hwndTrack = m_hWnd;
            ::_TrackMouseEvent(&csTME);
        } // if
    }
    else CancelHover();
} 

void CBootstrapButton::CancelHover()
{
    if (m_bMouseOnButton)
    {
        m_bMouseOnButton = FALSE;
        Invalidate();
    }
}
1

There are 1 answers

1
sergiol On

Try

this->ReleaseDC(dc);

instead of

dc->Detach();

at the end of your function.