By
Sahir Shah
22 - September - 2007
[Applies to : VC 2005 , Windows 98 or later ]
Mouseover is generally used for creating several kinds of visual effects in an application, such as changing the backcolor, text color, font size etc. when a mouse hovers over a control. In a C++/CLI (Windows Forms) application this is easily achieved using the MouseHover and MouseLeave events. For a MFC application we need to add handlers for a combination of three events to achieve this effect. A walkthrough of creating a sample application that draws a border around an edit box is used here to demonstrate how the mouseove event can be handled in a MFC application.
Create a MFC Dialog application in the Visual Studio IDE and select Project|Add Class in the menu bar. This will bring up the following dialog.

Select MFC class in this dialog and click on the "Add" button. This brings up the class wizard

Select CEdit as the base class, type in CTextBox as the name of the custom class and click "Finish". This generates the following class declaration in TextBox.h
class CTextBox : public CEdit {
DECLARE_DYNAMIC(CTextBox)
public:
CTextBox();
virtual ~CTextBox();
protected:
DECLARE_MESSAGE_MAP()
};
Next step is adding the WM_MOUSEMOVE , WM_MOUSEHOVER and WM_MOUSELEAVE message handlers to CTextBox. In TextBox.cpp add the following to the mesage map macro.
BEGIN_MESSAGE_MAP(CTextBox, CEdit) ON_WM_MOUSEMOVE() ON_MESSAGE(WM_MOUSEHOVER, OnMouseHover) ON_MESSAGE(WM_MOUSELEAVE, OnMouseLeave) END_MESSAGE_MAP()
Most message mappings can be added by clicking on the class and selecting the appropriate message in the mesage list in the properties window.

Some of the message mapping macros (e.g. ON_MESSAGE) may not be on the list, they have to be manually typed in. If in doubt about the format of the macro you can always verify it by looking into afxmsg_.h . the macro definition for these macros are as follows
#define ON_MESSAGE(message, memberFxn) \
{ message, 0, 0, 0, AfxSig_lwl, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< LRESULT (AFX_MSG_CALL CWnd::*)(WPARAM, LPARAM) > \
(memberFxn)) },
and
#define ON_WM_MOUSEMOVE() \
{ WM_MOUSEMOVE, 0, 0, 0, AfxSig_vwp, \
(AFX_PMSG)(AFX_PMSGW) \
(static_cast< void (AFX_MSG_CALL CWnd::*)(UINT, CPoint) > ( &ThisClass :: OnMouseMove)) },
After typing in the message map macro and the function names we add the function declarations to TextBox.h
class CTextBox : public CEdit {
DECLARE_DYNAMIC(CTextBox)
public:
CTextBox();
virtual ~CTextBox();
protected:
DECLARE_MESSAGE_MAP()
afx_msg void OnMouseMove(UINT nFlags, CPoint point);
afx_msg LRESULT OnMouseHover(WPARAM wparam, LPARAM lparam);
afx_msg LRESULT OnMouseLeave(WPARAM wparam, LPARAM lparam);
};
The WM_MOUSEHOVER and WM_MOUSELEAVE messages are not normally posted to the control so we need to call the TrackMouseEvent function from the WM_MOUSEMOVE event handler. This function call will cause four messages to be posted to the control when the mouse hovers over the control for a specified interval and when the mouse leaves the control. These four messages are :
WM_NCMOUSEHOVER, WM_NCMOUSELEAVE, WM_MOUSEHOVER and WM_MOUSELEAVE
Once we add the TrackMouseEvent function call to the mouse move event handler, whenever the mouse moves, this function will be called and if the mouse is hovering over the control, or is leaving the control, the two corresponding messages will be posted.
void CTextBox::OnMouseMove(UINT nFlags, CPoint point){
TRACKMOUSEEVENT tme;
tme.cbSize = sizeof(tme);
tme.hwndTrack = m_hWnd;
tme.dwFlags = TME_LEAVE|TME_HOVER;
tme.dwHoverTime = 1;
TrackMouseEvent(&tme);
}
My goal was to draw a colored border around a control containing static text when the mouse is moved over it. This can be done by getting the rectangular area of the control using the FrameRect member of the CDC class to draw a border around it.
LRESULT CTextBox::OnMouseHover(WPARAM wparam, LPARAM lparam) {
CDC* pDC = GetWindowDC();
CRect rect;
GetWindowRect(&rect);
rect.OffsetRect( -rect.left, -rect.top);
CBrush brush( RGB(0, 0, 255));
pDC->FrameRect( &rect, &brush);
ReleaseDC(pDC);
return true;
}
Since the intention was to add this effect to static text, I first tried using a static control and deriving from a CStatic control. I found that the messages do not get posted to the control regardless of TrackMouseEvent being called, so I decided to use an Edit control with the read only property set to true. However, this caused some annoying side effects such as the back color of the color changing to gray and the mouse pointer changing to a text insertion cursor (IDC_IBEAM) when the mouse was over the control.
One way of overcoming the mouse pointer problem is to add a handle to a cursor (HCURSOR) as an instance variable of CTextBox and getting a handle to an arrow IDC_ARROW cursor and changing the IDC_IBEAM cursor back to IDC_ARROW by calling SetCursor in the mouse move event handler. Changing the back color of the edit control from gray to another color can be achieved by repainting the background in the OnPaint event handler
void CTextBox::OnPaint(){
CPaintDC dc(this);
GetWindowText(text);
CDC* pDC = GetDC();
pDC->SetBkColor(RGB(255,255, 255));
CRect rc;
GetClientRect(&rc);
pDC->Rectangle(0, 0, rc.Width(), rc.Height());
pDC->TextOut(1, 1, text);
}
Note that the window text has to be stored and redrawn or else the text gets painted over when the background is repainted.
Finally drag an edit control from the toolbox to the dialog right click the control select "Add Variable" and type in CTextBox as the variable-type in the "Add Member Variable Wizard" dialog. Note that the type CTextBox will not be listed in the "Variable Type" drop down box. The name of the derived class has to be typed into the combo box, however the IDE inserts the line #include "textbox.h" into the dialog's header file when this is done. Build and run the application to see the MouseOver effect in action.