1

I've derived a Window from CWnd in which I create some OwnerDrawn Buttons. The Buttons are derived from CButton.

Now I want to change to BackgroundColor of my Buttons when the User is Hovering over it.

Therefore I already implemented that the OnMouseHover() and the OnMouseLeave() Messages are getting sent:

BEGIN_MESSAGE_MAP(CFooterButton, CButton)
   ON_WM_MOUSEHOVER()
   ON_WM_MOUSEMOVE()
   ON_WM_MOUSELEAVE()
END_MESSAGE_MAP()

void CFooterButton::OnMouseMove(UINT nFlags, CPoint point)
{

   //start tracking of Hover and Leave Event
   TRACKMOUSEEVENT tme;
   tme.cbSize = sizeof(TRACKMOUSEEVENT);
   tme.dwFlags = TME_HOVER | TME_LEAVE;
   tme.hwndTrack = m_hWnd;
   tme.dwHoverTime = HOVER_DEFAULT;
   TrackMouseEvent(&tme);

   CButton::OnMouseMove(nFlags, point);
}


void CFooterButton::OnMouseHover(UINT nFlags, CPoint point)
{


   HDC hdc = *GetWindowDC();

   SetBkColor(hdc,RGB(54, 125, 184));
   CButton::OnMouseHover(nFlags, point);
}

In the Debugger and Spy I can see that the code is getting called but nothing happens. Since I'm relatively new to MFC/c++ I assume I'm not using the DC correctly.. can someone explain me why it is not working and how i can fix it?

Jan Raufelder
  • 287
  • 7
  • 23
  • 1
    Changing the background in `OnMouseHover` wont do much, as the background color is reset when painting the background or the window. You could overwrite `OnEraseBkgn` and set the color there. – Karsten Koop May 24 '16 at 08:12
  • 1
    @KarstenKoop so I only need to call Invalidate() when OnMouseHover is getting called and then Handle OnEraseBkgn? – Jan Raufelder May 24 '16 at 08:19
  • I think a better approach would be to define the button as owner draw and paint the background color using the DC. – rrirower May 24 '16 at 12:33
  • 1
    You are trying too hard. The button already has all the hover functionality built in. All you have to do is set the `BS_OWNERDRAW` style and override [CButton::DrawItem](https://msdn.microsoft.com/en-us/library/y0k9f0a4.aspx). – IInspectable May 24 '16 at 13:14

1 Answers1

1

For anyone else who is struggling my Solution:

  • Create a member bool m_bHover = false in your Button class
  • implement OnMouseMove as provided in the Question to Track Hover and Leave
  • implement OnMouseHover

    void CFooterButton::OnMouseHover(UINT nFlags, CPoint point)
    {
       m_bHover = true;
       Invalidate();
       CButton::OnMouseHover(nFlags, point);
    }
    
  • implement OnMouseLeave

    void CFooterButton::OnMouseLeave()
    {
       m_bHover = false;
       Invalidate();
       CButton::OnMouseHover(nFlags, point);
    }
    
  • handle Hover effect in yourButtonClass::DrawItem (Invalidate() assures that it'll be called)

    void CFooterButton::DrawItem(LPDRAWITEMSTRUCT lpDrawItemStruct)
    {
        //default colors
        COLORREF textColor = RGB(202, 228, 251), backgroundColor = RGB(84, 150, 205);
    
        switch (lpDrawItemStruct->itemAction)
        {
        case ODA_DRAWENTIRE:
            //check if the user is just hovering over the button
           if (m_isHovered){
                 backgroundColor = RGB(54, 125, 184);
                 textColor = RGB(255, 255, 255); 
           }
           else{
    
                 backgroundColor = RGB(84, 150, 205);
                 textColor = RGB(202, 228, 251);
           }
           break;
    
        case ODA_FOCUS:
           //Button was clicked incase you want to change sth OnClick
           break;
        }
    
        CDC dc;
        dc.Attach(lpDrawItemStruct->hDC);
        dc.FillSolidRect(rect, backgroundColor);
        dc.SetTextColor(textColor);
    
        //your drawing code...
        //DrawFrameControl()etc..
        dc.Detach();
    }
    

Note: The lp-Structure has another itemAction -> ODA_SELECT refer to MSDN https://msdn.microsoft.com/de-de/library/windows/desktop/bb775802(v=vs.85).aspx

Jan Raufelder
  • 287
  • 7
  • 23
  • 1
    `itemAction` is a combination of different flags. You have to check `if (lpDrawItemStruct->itemAction&ODA_DRAWENTIRE)` (for a button this is always true). Also try changing to `tme.dwHoverTime = 10;` for better response. In `OnMouseHover`, change it to `if(!hover){hover=true;Invalidate();}` to reduce consecutive Invalidate calls... – Barmak Shemirani May 24 '16 at 17:16