2008-10-03 8 views
7

J'utilise SetCursor pour définir le curseur système sur ma propre image. Le code ressemble à ceci:SetCursor rétablit après un déplacement de souris

// member on some class 
HCURSOR _cursor; 

// at init time 
_cursor = LoadCursorFromFile("somefilename.cur"); 

// in some function 
SetCursor(_cursor); 

Quand je fais le curseur ne change, mais le premier message de déplacement de la souris, il change au système par défaut flèche curseur. C'est le seul code du projet qui définit le curseur. Que dois-je faire pour que le curseur reste tel que je l'ai défini?

Répondre

9

Il semble que j'ai deux options. Le premier est celui que Mark Ransom a suggéré ici, qui est de répondre au message WM_SETCURSOR de Windows et d'appeler SetCursor à ce moment en fonction de l'emplacement de la souris. Normalement, Windows ne vous enverra que WM_SETCURSOR lorsque le curseur se trouve sur votre fenêtre, vous ne pourrez donc que placer le curseur dans votre fenêtre.

L'autre option consiste à définir le curseur par défaut pour la poignée de fenêtre en même temps que j'appelle SetCursor. Cela modifie le curseur défini par le gestionnaire par défaut à WM_SETCURSOR. Ce code ressemblerait à quelque chose comme ceci:

// defined somewhere 
HWND windowHandle; 
HCURSOR cursor; 

SetCursor(cursor); 
SetClassLong(windowHandle, GCL_HCURSOR, (DWORD)cursor); 

Si vous utilisez la deuxième méthode, vous devez appeler les deux SetCursor et SetClassLong ou votre curseur ne sera pas mise à jour jusqu'à ce que le prochain mouvement de la souris.

2

Vous devez faire en sorte que votre poignée HCURSOR ne soit pas hors de portée. Lorsque la souris se déplace, les messages Windows commencent à voler partout, et cela effacera votre poignée (dans l'exemple ci-dessus).

Faites d'un HCURSOR un membre privé de la classe et utilisez ce handle lorsque vous appelez LoadCursor ...() et SetCursor(). Lorsque vous avez terminé, n'oubliez pas de le libérer et de le nettoyer, sinon vous vous retrouverez avec une fuite de ressources.

1

Ce comportement est destiné à être ainsi. Je pense que la solution la plus simple est la suivante: Lors de la création de votre classe de fenêtre (RegisterClass || RegisterClassEx), définissez le membre WNDCLASS.hCursor || WNDCLASSEX.hCursor sur NULL. Comme @Heinz Traub a déclaré que le problème vient du curseur défini sur l'appel RegisterClass ou RegisterClassEx

+0

Passer à NULL n'a pas résolu le problème. Au lieu de permettre au curseur de changer, le curseur était toujours <-> au lieu de la flèche normale. Et les messages messages WM_SETCURSOR étaient toujours envoyés, comme je pouvais vérifier en utilisant Spy ++ 64bit. Cependant, j'ai augmenté parce que vous m'avez fait apprendre quelque chose de nouveau. – sergiol

0

Vous avez probablement le code comme:

BOOL CMyWnd::RegisterWindowClass() 
{ 
    WNDCLASS wndcls; 
    // HINSTANCE hInst = AfxGetInstanceHandle(); 
    HINSTANCE hInst = AfxGetResourceHandle(); 

    if (!(::GetClassInfo(hInst, _T("MyCtrl"), &wndcls))) 
    { 
     // otherwise we need to register a new class 
     wndcls.style   = CS_DBLCLKS | CS_HREDRAW | CS_VREDRAW; 
     wndcls.lpfnWndProc  = ::DefWindowProc; 
     wndcls.cbClsExtra  = wndcls.cbWndExtra = 0; 
     wndcls.hInstance  = hInst; 
     wndcls.hIcon   = NULL; 
     wndcls.hCursor   = AfxGetApp()->LoadStandardCursor(IDC_ARROW); 
     wndcls.hbrBackground = (HBRUSH) (COLOR_3DFACE + 1); 
     wndcls.lpszMenuName  = NULL; 
     wndcls.lpszClassName = _T("MyCtrl"); 

     if (!AfxRegisterClass(&wndcls)) 
     { 
      AfxThrowResourceException(); 
      return FALSE; 
     } 
    } 

    return TRUE; 
} 

où le wndcls.hCursor dit ce que le curseur sera utilisé lorsque WM_SETCURSOR message est jeté; cela arrive chaque fois qu'il se produit un mouvement de souris et pas seulement.

Je résolu un problème similaire de cette façon:

Dans la classe carte de message ajouter une entrée pour le message WM_SETCURSOR:

BEGIN_MESSAGE_MAP(CMyWnd, CWnd) 
    //... other messages 
    ON_WM_SETCURSOR() 
END_MESSAGE_MAP() 

Ajoutez la méthode OnSetCursor, qui remplacera la classe parente la mise en œuvre :

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{ 
    if (SomeCondition()) 
     return FALSE; 

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

Explication: quand SomeCondition() est vrai, vous ne serez pas appeler la mise en œuvre des parents.Peut-être que vous voulez toujours avoir un curseur non remplacé avec le comportement de la classe parent, vous donc juste besoin d'une méthode encore plus courte:

BOOL CMyWnd::OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message) 
{ 
    return FALSE; 
} 

Et la déclaration de la méthode dans le fichier d'en-tête est:

afx_msg BOOL OnSetCursor(CWnd* pWnd, UINT nHitTest, UINT message);