Twitter iPhone pliant OnePlus 11 PS5 Disney+ Orange Livebox Windows 11

Problème avec survol de boutons

15 réponses
Avatar
Roger
Bonjour,
Fenêtre dialogue créee dans fichier ressource avec contrôles statiques et
deux boutons.
Dans la CALLBACK du dialogue je teste WM_MOUSEMOVE pour récupérer la main
chaque fois que la souris se déplace sur la fenêtre du dialogue.
Puis j'utilise ChildWindowFromPoint pour savoir sur quel contrôle de la
fenêtre dialogue la souris se trouve.
La fonction ChildWindowFromPoint me fournit correctement le handle de chaque
contrôle statique chaque fois que je le survole, par contre quand je survole
les boutons, la fonction ChildWindowFromPoint continue à me fournir le
handle de la fenêtre parente (celle du dialogue) ce qui fait que je ne
détecte pas les boutons.
J'ai essayé ChildWindowFromPointEx avec le paramètre CWP_ALL, c'est pareil.
J'ai essayé de rajouter le paramètre WS_CHILD dans la description des
boutons du fichier ressource, c'est pareil.
De toutes façons les contrôles statiques du fichier ressource n'ont pas le
paramètre WS_CHILD et pourtant ça marche.
Je construis moi-même mes contrôles statiques et mes boutons (paramètres
SS_OWNERDRAW et BS_OWNERDRAW)
Est-ce normal ?
Merci

10 réponses

1 2
Avatar
Christian ASTOR
Roger a écrit :
Bonjour,
Fenêtre dialogue créee dans fichier ressource avec contrôles statiques et
deux boutons.
Dans la CALLBACK du dialogue je teste WM_MOUSEMOVE pour récupérer la main
chaque fois que la souris se déplace sur la fenêtre du dialogue.
Puis j'utilise ChildWindowFromPoint pour savoir sur quel contrôle de la
fenêtre dialogue la souris se trouve.
La fonction ChildWindowFromPoint me fournit correctement le handle de chaque
contrôle statique chaque fois que je le survole, par contre quand je survole
les boutons, la fonction ChildWindowFromPoint continue à me fournir le
handle de la fenêtre parente (celle du dialogue) ce qui fait que je ne
détecte pas les boutons.



Si tu es sur un bouton, WM_MOUSEMOVE n'est plus sur la fenêtre
principale...
Avatar
Roger
Si tu es sur un bouton, WM_MOUSEMOVE n'est plus sur la fenêtre
principale...



Bonjour,
Oui, je viens de retester effectivement quand je suis sur un bouton je ne
reçois plus de message WM_MOUSEMOVE de Windows exactement comme quand la
souris se trouve en dehors de la fenêtre du dialogue.
Je n'ai peut-être pas bien compris le principe mais je ne vois pas la
logique car ChildWindowFromPoint est sensée détecter toutes les fenêtres
filles or un contrôle bouton qui se trouve sur la fenêtre dialogue c'est
bien une fenêtre fille du dialogue, la preuve c'est que j'obtiens bien son
handle par GetDlgItem(handledudialogue, ID_dubouton).
Par ailleurs ChildWindowFromPoint est sensée aussi fournir un handle égal à
NULL lorsque la souris se trouve en dehors de la fenêtre dialogue, or je
n'ai jamais ce cas là car quand je suis en dehors ou sur un bouton je ne
reçois plus le message WM_MOUSEMOVE donc je ne passe plus sur la fonction
ChildWindowFromPoint.

En conclusion, si je pouvais avoir une explication succinte de la logique...
et ensuite comment détecter sur quel bouton se trouve la souris ?
Merci
Avatar
Christian ASTOR
Roger a écrit :
Si tu es sur un bouton, WM_MOUSEMOVE n'est plus sur la fenêtre
principale...



Bonjour,
Oui, je viens de retester effectivement quand je suis sur un bouton je ne
reçois plus de message WM_MOUSEMOVE de Windows exactement comme quand la
souris se trouve en dehors de la fenêtre du dialogue.
Je n'ai peut-être pas bien compris le principe mais je ne vois pas la
logique car ChildWindowFromPoint est sensée détecter toutes les fenêtres
filles or un contrôle bouton qui se trouve sur la fenêtre dialogue c'est
bien une fenêtre fille du dialogue, la preuve c'est que j'obtiens bien son
handle par GetDlgItem(handledudialogue, ID_dubouton).
Par ailleurs ChildWindowFromPoint est sensée aussi fournir un handle égal à
NULL lorsque la souris se trouve en dehors de la fenêtre dialogue, or je
n'ai jamais ce cas là car quand je suis en dehors ou sur un bouton je ne
reçois plus le message WM_MOUSEMOVE donc je ne passe plus sur la fonction
ChildWindowFromPoint.

En conclusion, si je pouvais avoir une explication succinte de la logique...
et ensuite comment détecter sur quel bouton se trouve la souris ?



C'est logique de ne plus recevoir WM_MOUSEMOVE sur la fenêtre... si l'on
n'est plus sur la fenêtre, soit en dehors par exemple.

Il faut donc utiliser soit un SetCapture()-ReleaseCapture(), soit un
hook local.
Avatar
Roger
Il faut donc utiliser soit un SetCapture()-ReleaseCapture(), soit un
hook local.




Re-bonjour,
J'avais déjà essayé de mettre un SetCapture(handledudialogue) dès le
WM_INITDIALOG ainsi qu'un ReleaseCapture() dans le WM_CLOSE du process du
dialogue, mais ça ne change rien, je ne reçois toujours pas le message
WM_MOUSEMOVE lorsque je survole un bouton.
J'ai même essayé avec SetCapture(handledubouton), c'est kifkif !

Hook ? J'avais effectivement pensé à SetWindowsHookEx ainsi
qu'éventuellement à sous-classer la WinProc du bouton pour installer un
WM_MOUSEMOVE à l'intérieur de la procédure de sous-classement, mais avant
d'en arriver là, j'espérais qu'il existait un moyen plus élégant...

A noter que la logique de la fenêtre fille m'est toujours pas apparue
claire:
1.- quand je survole la fenêtre du dialogue là où il n'y a aucune fenêtre
fille (aucun contrôle), je reçois bien le message WM_MOUSEMOVE !!!!
2.- quand je survole une fenêtre fille du dialogue qui est un contrôle
static, je reçois bien le message WM_MOUSEMOVE !!!!
3.- quand je survole une fenêtre fille du dialogue qui est un contrôle
bouton, je ne reçois plus le message WM_MOUSEMOVE !!!!

Serait-ce qu'il y aurait des vrais filles et des fausses filles ???!!!

Merci
Avatar
Christian ASTOR
Roger a écrit :
Il faut donc utiliser soit un SetCapture()-ReleaseCapture(), soit un
hook local.




Re-bonjour,
J'avais déjà essayé de mettre un SetCapture(handledudialogue) dès le
WM_INITDIALOG ainsi qu'un ReleaseCapture() dans le WM_CLOSE du process du
dialogue, mais ça ne change rien, je ne reçois toujours pas le message
WM_MOUSEMOVE lorsque je survole un bouton.
J'ai même essayé avec SetCapture(handledubouton), c'est kifkif !



Car il ne faut pas appeler SetCapture() sur WM_INITDIALOG (trop tôt
entre autres) (ça se met en général sur un WM_LBUTTONDOWN)


1.- quand je survole la fenêtre du dialogue là où il n'y a aucune fenêtre
fille (aucun contrôle), je reçois bien le message WM_MOUSEMOVE !!!!
2.- quand je survole une fenêtre fille du dialogue qui est un contrôle
static, je reçois bien le message WM_MOUSEMOVE !!!!
3.- quand je survole une fenêtre fille du dialogue qui est un contrôle
bouton, je ne reçois plus le message WM_MOUSEMOVE !!!!

Serait-ce qu'il y aurait des vrais filles et des fausses filles ???!!!



C'est parce que le contrôle BUTTON intercepte WM_MOUSEMOVE dans sa
WndProc() d'origine.
Avatar
Roger
Car il ne faut pas appeler SetCapture() sur WM_INITDIALOG (trop tôt
entre autres) (ça se met en général sur un WM_LBUTTONDOWN)



Je comprends mieux pourquoi ça ne marche pas, mais le WM_LBUTTONDOWN ne me
convient pas car je veux changer le curseur sans avoir à cliquer sur le
bouton, au simple survol.



Serait-ce qu'il y aurait des vrais filles et des fausses filles ???!!!



C'est parce que le contrôle BUTTON intercepte WM_MOUSEMOVE dans sa
WndProc() d'origine.



C'est plus clair ainsi, d'ailleurs je viens de tester en sous-classant la
WinProc du bouton et en ne mettant dans sa procédure de sous-classement
qu'un WM_MOUSEMOVE dans lequel je mets une bascule à true dès que j'y passe.
En parallèle le laisse un WM_MOUSEMOVE dans la procédure du dialogue
(fenêtre parente) pour mettre la même bascule à false lorsque j'y passe. Les
deux procédures renvoyant par un WM_NOTIFY à la même séquence de code de la
fenêtre du dialogue qui reçoit donc un code à 0 ou à 1 selon la valeur de la
bascule.
Ca marche, quand je survole le bouton la séquence de code du NOTIFY reçoit
un 1, quand j'en sors la même séquence reçoit un 0.
Cependant ce n'est pas parfait, car ceci suppose que lorsque je ne survole
plus le bouton je me retrouve dans la fenêtre parente du dialogue ce qui est
normalement obligatoire et qui permet la mise à false de la bascule. Mais,
si je sors du survol du bouton d'un mouvement très vif pour aller
directement carrément en dehors de la fenêtre principale du dialogue, le
survol de la fenêtre principal est trop bref et Windows n'a pas le temps
d'envoyer le message WM_MOUSEMOVE à la fenêtre principale et ma bascule
reste à 1 !!!!

Il ne me reste donc plus qu'à tester avec le hook, ce que je voulais éviter
au départ... sauf si tu vois une autre solution.

En tout cas merci pour ton aide.
Avatar
Christian ASTOR
Roger a écrit :
Car il ne faut pas appeler SetCapture() sur WM_INITDIALOG (trop tôt
entre autres) (ça se met en général sur un WM_LBUTTONDOWN)



Je comprends mieux pourquoi ça ne marche pas, mais le WM_LBUTTONDOWN ne me
convient pas car je veux changer le curseur sans avoir à cliquer sur le
bouton, au simple survol.



Tu n'avais pas parlé de changer le curseur dans ton premier post.
Si c'est ce que tu veux faire, c'est juste avec WM_SETCURSOR
Avatar
Roger

Tu n'avais pas parlé de changer le curseur dans ton premier post.
Si c'est ce que tu veux faire, c'est juste avec WM_SETCURSOR



Comme quoi j'aurais dû tout dire.
Pour info, je venais de résoudre le problème du survol sans passer par le
hook, en fait dans ma solution précédente avec le WM_MOUSEMOVE, je n'ai pas
besoin du WM_MOUSEMOVE dans la fenêtre principale du dialogue qui me servait
à savoir quand je ne survolais plus. Il me suffit de garder le WM_MOUSEMOVE
de la procédure de sous-classement du bouton et d'y rajouter le
SetCapture(hwndlocaldubouton) qui cette fois-ci, effectivement, fonctionne
et le ChildWindowFromPointEx me donne soit le hwndlocaldubouton soit NULL si
je suis en dehors. De plus cette fois-ci quand je fais un mouvement très vif
de la souris pour partir du bouton et me retrouver sur une fenêtre non gérée
par le même thread, j'ai le temps cette fois-ci de passer une fois encore
dans le message WM_MOUSEMOVE de détecter un NULL et de pouvoir faire le
ReleaseCapture.

Je vais donc regarder le WM_SETCURSOR merci, mais je vois déjà des
paramètres qui ne me disent rien: hit-test & mouse-message identifier.....
Avatar
Roger

Je vais donc regarder le WM_SETCURSOR merci, mais je vois déjà des
paramètres qui ne me disent rien: hit-test & mouse-message identifier.....

Bon, je n'ai pas réussi à changer le curseur en "main" lors du survol sur
le bouton considéré:


lorsque j'ai testé sous le WM_SETCURSOR de ma fenêtre principale que le HWND
renvoyé par wParam est bien le handle du bouton, je fais un SetCursor(main)
(main est l'objet plus haut dans le code d'un LoadCursor) et il ne se passe
rien. Je sors de la procédure par un return false (le return true bloque la
gestion du curseur), faut dire que dans la doc API du WM_SETCURSOR il est
question du DefWindowProc, or dans mon cas je n'en ai pas en fin de
procédure car ma fenêtre principale est un dialogue (créée par
CreateDialog).

A défaut d'y arriver par WM_SETCURSOR et SetCursor, j'ai fait un:
SetClassLong((HWND)wParam, GCL_HCURSOR , (LONG)main) et ça c'est radical, ça
marche tout de suite, sauf que ça me change le curseur en "main" sur tous
les boutons (ce qui est logique puisque je modifie la classe bouton) et pas
seulement sur celui que je voulais.
Avatar
Christian ASTOR
Roger a écrit :

Je vais donc regarder le WM_SETCURSOR merci, mais je vois déjà des
paramètres qui ne me disent rien: hit-test & mouse-message identifier.....

Bon, je n'ai pas réussi à changer le curseur en "main" lors du survol sur
le bouton considéré:


lorsque j'ai testé sous le WM_SETCURSOR de ma fenêtre principale que le HWND
renvoyé par wParam est bien le handle du bouton, je fais un SetCursor(main)
(main est l'objet plus haut dans le code d'un LoadCursor) et il ne se passe
rien. Je sors de la procédure par un return false (le return true bloque la
gestion du curseur), faut dire que dans la doc API du WM_SETCURSOR il est
question du DefWindowProc, or dans mon cas je n'en ai pas en fin de
procédure car ma fenêtre principale est un dialogue (créée par
CreateDialog).




Dans une DialogBox, il faut utiliser DWLP_MSGRESULT
Par exemple, pour changer le curseur en mimine juste sur un Edit
IDC_EDIT2, on fait =>

case WM_SETCURSOR:
{
if((HWND) wParam == GetDlgItem(hWnd, IDC_EDIT2))
{
SetCursor(LoadCursor(NULL, IDC_HAND));
SetWindowLong(hWnd, DWLP_MSGRESULT, TRUE);
}
else
return FALSE;
return TRUE;
}
break;
1 2