Changing cursor to a hand in MFC

steva
steva used Ask the Experts™
on
Is there a way to change the cursor to a hand in MFC when it passes over a button?

Thanks
Comment
Watch Question

Do more with

Expert Office
EXPERT OFFICE® is a registered trademark of EXPERTS EXCHANGE®

Commented:
SetCursor function will set it:
::SetCursor(::LoadCursor(NULL, IDC_HANDCUR));

(AfxGetApp()->SetCursor(AfxGetApp()->LoadCursor(IDC_HANDCUR));)

You can use this function for a button like here:
myButton.SetCursor( ::LoadCursor(NULL, IDC_HANDCUR) );
http://msdn.microsoft.com/en-us/library/8w6ks9y7(VS.80).asp

When mouse moves over a window, this window receives WM_SETCURSOR (OnSetCursor method to override in am MFC class) and WM_MOUSEMOVE (OnMouseMove).
http://msdn.microsoft.com/en-us/library/7ykcbyxt(VS.80).asp

Load this cursor in the beginning of your app and set when needed.

Author

Commented:
pgnatyuk,

What do I need to #include to get access SetCursor.  I running VC6.0.  Both of your links are dead.

Thanks

Commented:
Nothing special. It is standard MFC method of CWnd.
Sorry for the broken links. Check now - this time it's done in IE:
http://msdn.microsoft.com/en-us/library/8w6ks9y7(VS.80).aspx
 
Exploring SQL Server 2016: Fundamentals

Learn the fundamentals of Microsoft SQL Server, a relational database management system that stores and retrieves data when requested by other software applications.

Commented:
OnSetCursor: http://msdn.microsoft.com/en-us/library/7ykcbyxt(VS.80).aspx
The idea is simple:
1. Load a cursor on the application start. For example in OnInitDialog for an MFC dialog-based app. Or in OnCreate of the window.
m_hMyHand=AfxGetApp()->LoadCursor(IDC_HANDCUR);
2. If you need this cursor in a special window, in OnSetCursor set this cursor to this window. When the mouse will move over the window, the user will see this cursor:
 BOOL CMyView::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
      {
            if ( m_hMyHand )
              {
                  ::SetCursor(m_hMyHand);
                  return TRUE;
              }

            return CView::OnSetCursor(pWnd, nHitTest, message);
      }

 3. If you need it for a button in a dialog:
BOOL CMyDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message)
{
    if (pWnd == GetDlgItem(IDC_MYBTN))
    {
           ::SetCursor(m_hMyHand);
           return TRUE;
    }
    return CDialog::OnSetCursor(pWnd, nHitTest, message);
}
 
More info:
Microsoft Support. How to change the mouse pointer for a window in MFC by using Visual C++
http://support.microsoft.com/kb/131991
 

Author

Commented:
In your step 2 above it looks like you have OnSetCursor looking for the hand cursor.  In my case I have two buttons in the dialog that I want to set the cursor for.  See the attached image.  It seems like I should be looking for these buttons at the top of OnSetCursor and then changing the cursor if I find them.  Or am I missing something?

Thanks for your help.
wizard.png

Commented:
Try and  will have an answer.

Author

Commented:
I'm not having a lot of success.  Here's the code I have:

The first problem is that my WINVER is 0x400 so  IDC_HAND isn't defined in WINUSER.H.  I'm running on XP, but VC6.0 must set the WINVER to the older value.  I'll worry about this later.  For now I'm just trying to use a cursor that is defined for WINVER 0x400, like IDC_CROSS.

I break into the ::SetCursor line ok in the OnSetCursor handlerwhen I roll over my button, but the cursor disappears when the mouse is over the button instead of changing to a cross.  

Any ideas?
BOOL CmyApp::OnInitDialog()

   .
   .
   .
	winver = WINVER;  // 0x400

	m_Hand=AfxGetApp()->LoadCursor(IDC_CROSS);
   .
   .
   .


BOOL CRegisterDlg::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{
	CWnd * p;
	p =GetDlgItem(IDC_BUTTON_GET_LICENSE);
	
	if(p == pWnd) {
		::SetCursor(m_Hand);
		return TRUE;
	}

	return CDialog::OnSetCursor(pWnd, nHitTest, message);

Open in new window

Commented:
>>I'm running on XP, but VC6.0 must set the WINVER to the older value.
No.
Set whatever you need in the stdafx.h.  
Of course, I do not remember for sure, it was a million years ago, but IDC_HAND is older than me. Check something like that:
CWinApp* pApp = AfxGetApp();
m_hCursor = pApp->LoadStandardCursor(IDC_HAND);

I do not understand what does not work. Do you see the cursor? Can you set this cursor for your app and see if the cursor exists? If you set a breakpoint in OnSetCursor method, do you see that this method is called and works?

You can make your button class and add OnSetCursor method. When the mouse cursor will be over the button, in this method you will call SetCursor.

You do not capture the mouse, I hope.

Author

Commented:
I can see in the WINUSER.H that my code links with that IDC_HAND is not defined.  (See attached image.) So that seems to be the answer there. I'll play with setting a higher WINVER later.  For now I should be able to get one of the defined cursors to appear when I roll over my button.

"If you set a breakpoint in OnSetCursor method, do you see that this method is called and works?"

Yes, I can set a breakpoint on line 20 of the attached code above and I stop when I roll over my button.  But then executing the code
                                  ::SetCursor(m_Hand);
                               return TRUE;

where m_hand was set earlier with

HCURSOR   m_Hand;
                    m_Hand=AfxGetApp()->LoadCursor(IDC_CROSS);

makes the cursor disappear instead of changing to a hand. When the mouse rolls off of the button the normal arrow cursor comes back.


Cursors.png
Commented:
Seems like you set NULL instead of a valid cursor handle.

This:
HCURSOR   m_Hand;
is in the class interface, in the h-file.

This:
 m_Hand=AfxGetApp()->LoadCursor(IDC_HAND);

in OnInitDialog, if you have a dialog based app.
You can set:
m_Hand = ::LoadCursor(NULL, IDC_HAND);

Now, remove all breakpoints. Simply run the app and test the cursor. If you don't see the cursor of the screen, add a trace to check the you use a valid handle (not NULL).

Author

Commented:
Got it!

Yes, the m_Hand cursor was NULL.  It turns out that

                                    m_Hand=AfxGetApp()->LoadCursor(IDC_CROSS);  

in OnInit loads NULL while

                                  m_Hand = ::LoadCursor(NULL, IDC_CROSS);

in OnInit  loads a real cursor.

Using the second example the cursor worked as I wanted:  when the mouse rolls over the button it changes to a cross (+) and goes back to an arrow when the mouse rolls off of the button.

To get the IDC_HAND cursor instead of IDC_CROSS I had to modify the WINUSER.H file to read

#if( WINVER >= 0x0400)
#define IDC_HAND

instead of

#if( WINVER >= 0x0500)
#define IDC_HAND

#defining WINVER in stdafx.h to 0x0500 didn't do it.

Thanks for the help.  I gave you the points.


Author

Commented:
Question is answered.

Do more with

Expert Office
Submit tech questions to Ask the Experts™ at any time to receive solutions, advice, and new ideas from leading industry professionals.

Start 7-Day Free Trial