Control et Mouse [Résolu]

cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 14:02 - Dernière réponse : cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention
- 7 janv. 2006 à 10:32
Bonjour,
Je suis entrain de faire un Control, appelons-le "x" (qui dérive de Usercontrol) qui devra faire certaines actions lorsque la souris est au-dessus de lui.
Mon problème, c'est que ce Control ("x") possède d'autres Control, disons "y" (en loccurance, y'a pour le moment des Labels et une PictureBox) et que lorsque ma souris passe sur l'un des "y" qui se trouve dans "x" je reçois un MouseLeave puis un MouseEnter quand la souris entre repectivement quitte "y" (mais reste toujours dans "x" !).
Et ça me pose bien-entendu tout un tas de problème...

J'aurais aimé savoir comment régler ce problème le plus proprement possible (autrement dit, comment faire pour savoir si la souris est dans un Control, y compris un des sous-Control).

(J'espère que la question était claire )
Merci d'avance aux réponses !


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
Afficher la suite 

Votre réponse

26 réponses

Meilleure réponse
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 6 janv. 2006 à 13:45
3
Merci
Un peu trop vite d'ailleurs, j'ai écrit une connerie ^^ :

public class ContainerLevelMouseEventsMessageFilter : IMessageFilter
{
public ContainerLevelMouseEventsMessageFilter(Control container)
{
if ( container = = null )
throw new ArgumentNullException("container");


this._container = container;


this._container.Disposed += new EventHandler(_container_Disposed);
}


private Control _container = null;
private bool _isEntered = false;


private const int WM_MOUSEMOVE = 0x0200;


#region Membres de IMessageFilter


public bool PreFilterMessage(ref Message m)
{
if ( m.Msg == WM_MOUSEMOVE )
{
// détermine si la cible est notre contrôle ou est contenue par notre contrôle
Control ctrl = Control.FromHandle(m.HWnd); if ( ctrl !null && (ctrl this._container || this._container.Contains(ctrl)) )
{
if ( !this._isEntered )
{
// levée de MouseEnter
this.OnMouseEnter();


this._isEntered = true;
}


// récupération du point (en coordonnées du contrôle cible)
Point pt = new Point(m.LParam.ToInt32());


// conversion en coordonnée du contrôle
Point containerPoint;
if ( ctrl != this._container )
containerPoint = this._container.PointToClient(ctrl.PointToScreen(pt));
else
containerPoint = pt;


// levée de MouseMove
this.OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, containerPoint .X, containerPoint.Y, 0));
}
else
{
// si la cible n'est pas un enfant, et que la sortie n'a pas encore été notifiée
if ( this._isEntered )
{
// levée de MouseLeave
this.OnMouseLeave();


this._isEntered = false;
}
}
}


return false;
}


#endregion


private void _container_Disposed(object sender, EventArgs e)
{
try
{
this._container = null;
Application.RemoveMessageFilter(this);
}
catch
{
}
}


public event MouseEventHandler MouseMove;
public event EventHandler MouseEnter;
public event EventHandler MouseLeave;


protected virtual void OnMouseMove(MouseEventArgs e)
{
if ( this.MouseMove != null )
this.MouseMove(this._container, e);
}


protected virtual void OnMouseLeave()
{
if ( this.MouseLeave != null )
this.MouseLeave(this._container, EventArgs.Empty);
}


protected virtual void OnMouseEnter()
{
if ( this.MouseEnter != null )
this.MouseEnter(this._container, EventArgs.Empty);
}
}

/*
coq
MVP Visual C#
*/

Merci cs_coq 3

Avec quelques mots c'est encore mieux Ajouter un commentaire

Codes Sources a aidé 84 internautes ce mois-ci

Commenter la réponse de cs_coq
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 4 janv. 2006 à 14:26
0
Merci
passe par un override de WndProc

Sébastien FERRAND
[MVP C#]
Commenter la réponse de sebmafate
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 18:25
0
Merci
Salut et merci de la réponse.
A vrai dire j'ai toujours eu un peu de peine avec le WndProc, comme savoir par exemple quel message m'intéresse?
Tu pourrais un peu m'aiguiller stp? Merci


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever /auteurdetail.aspx?ID=13319
Commenter la réponse de cs_Bidou
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 4 janv. 2006 à 19:40
0
Merci
WM_MOUSEMOVE

Sébastien FERRAND
[MVP C#]
Commenter la réponse de sebmafate
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 21:06
0
Merci
Désolé mais je vois pas trop
Pas trop l'habitude de travailler avec ça je dois dire.

Je dois faire qqch comme ça ou bien ?



protected
override
void WndProc(
ref
Message m)
{

base.WndProc(
ref m);
if (m.Msg == WM_MOUSEMOVE) // Comment savoir que vaut WM_MOUSEMOVE ??
{
// Et ici on fait quoi ?
}

}


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever /auteurdetail.aspx?ID=13319
Commenter la réponse de cs_Bidou
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 4 janv. 2006 à 21:55
0
Merci
alors...

WM_MOUSEMOVE = 0x200;
WM_MOUSELEAVE = 0x2a3;

(merci reflector ;))

Sébastien FERRAND
[MVP C#]
Commenter la réponse de sebmafate
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 22:00
0
Merci
J'ai réussi à trouver les valeurs sur le net mais je sais toujours pas ce que je dois faire avec lol.
Hum...


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever /auteurdetail.aspx?ID=13319
Commenter la réponse de cs_Bidou
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 4 janv. 2006 à 22:16
0
Merci
ok... on va faire plus complet :)



private
const
int WM_MOUSEMOVE = 0x200;

private
const
int WM_MOUSELEAVE = 0x2a3;



protected
override
void WndProc(
ref
Message m)
{

switch (m.Msg) {

case WM_MOUSELEAVE :
isMouseHover =
false;
_MouseLeave(
EventArgs.Empty);

break;

case WM_MOUSEMOVE :

if (!isMouseHover)
_MouseEnter(
EventArgs.Empty);
_MouseMove(
EventArgs.Empty);

break;
}

base.WndProc(
ref m);
}



protected
virtual
void _MouseEnter(
EventArgs e) {

Console.WriteLine(
"La souris est entr‚e dans le controle");
}



protected
virtual
void _MouseLeave(
EventArgs e) {

Console.WriteLine(
"La souris a quitt‚ le controle");
}



protected
virtual
void _MouseMove(
EventArgs e) {

Console.WriteLine(
"La souris bouge au dessus du controle");
}

Sébastien FERRAND
[MVP C#]
Commenter la réponse de sebmafate
sebmafate 4947 Messages postés lundi 17 février 2003Date d'inscription 14 février 2014 Dernière intervention - 4 janv. 2006 à 22:28
0
Merci
ooops... j'm'a trompé

case WM_MOUSEMOVE :
if (!isMouseHover) {
isMouseHover = true;
_MouseEnter(EventArgs.Empty);
}
_MouseMove(EventArgs.Empty);
break;


Sébastien FERRAND
[MVP C#]
Commenter la réponse de sebmafate
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 22:43
0
Merci
Ben si je met ce code, alors j'observe dans ma Form de test, que quand j'entre dans le Control il m'affiche correctement ce qu'il faut dans la console (il dit qu'il est entré et que la souris bouge au dessus) mais le problème est toujours le même : la souris est à l'intérieur du Control et lorsqu'elle passe sur un label (compris dans le Control) ca vient écrit que la souris a quitter le Control (hors, ce n'est pas le cas, dumoins je ne veux justement pas que ça le soit !).
Je sais pas si tu vois ?


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever /auteurdetail.aspx?ID=13319
Commenter la réponse de cs_Bidou
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 4 janv. 2006 à 22:51
0
Merci
Le problème c'est que le message WM_MOUSEMOVE est envoyé directement au Label et non pas relayé par le contrôle.
Je pense que le salut peut être dans l'utilisation d'un filtre au niveau de l'application (IMessageFilter) avec vérification pour savoir si le contrôle destinataire est enfant du contrôle "x".
Ou carrement en mode bourrin (mais probablement moins gourmand en ressources) regarder si les coordonnées du pointeur sont dans le rectangle du contrôle "x".

/*
coq
MVP Visual C#
*/
Commenter la réponse de cs_coq
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 4 janv. 2006 à 23:08
0
Merci
En fait, l'idée est toute simple (ce que je veux faire finalement) : quand on entre sur un Control, je veux le colorier. Et quand on sort, je veux qu'il reprenne sa forme normal. Ca marche, sauf que quand on entre sur un label qui se trouve dans ce Control ben il reprend sa forme normal alors que ma souris est toujours dans le Control.
C'est vraiment si compliqué de faire ça ? lol


<HR>


[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever /auteurdetail.aspx?ID=13319
Commenter la réponse de cs_Bidou
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 5 janv. 2006 à 01:23
0
Merci
Salut Bidou

Comme le dit Coq le plus simple c'est encore de tester les coordonnées du pointeur.

public class MyControl : UserControl
{
public MyControl( ) : base( )
{
// Une PictureBox pour l'exemple.
PictureBox pb = new PictureBox( );
pb.BackColor = Color.Lime;
pb.Location = new Point( 10, 10 );
pb.Size = new Size( 100, 100 );
this.Controls.Add( pb );
}


protected override void OnMouseEnter( EventArgs e )
{
base.OnMouseEnter( e );


this.BackColor = Color.Red;
}


protected override void OnMouseLeave( EventArgs e )
{
base.OnMouseLeave( e );


if ( !this.ClientRectangle.Contains( this.PointToClient( Control.MousePosition ) ) )
{
this.BackColor = SystemColors.Control;
}
}
}
Commenter la réponse de Lutinore
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 5 janv. 2006 à 10:11
0
Merci
Salut Lutinore,
Oui en fait j'avais cette solution avant que je pose la question, mais elle me déplait très fortement pour plusieurs raison. Une des raisons principale c'est qu'après je ne peux plus utiliser le tooltip (qui fonctionne avec MouseHover) : Le tooltip est displayé seulement quand on est sur le Control à proprement dit, mais pas quand on est sur un sous-Control.
Une autre raison, c'est que si je quitte brusquement le Control avec le souris, on dirait qu'il n'a pas le temps d'effectuer le OnLeave et mon Control reste en couleur, alors que le curseur est en dehors.

J'aimerais bien une solution général, qui me permet de ne pas être notifié des events qui se produisent sur un de ces sous-controls (ou autres solutions propres)
Je ne sais pas si c'est très clair ??


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
Commenter la réponse de cs_Bidou
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 5 janv. 2006 à 18:36
0
Merci
Peut être si tu abonnes tous les MouseMove des contrôles enfants sur le même évènement du contrôle parent ça te permet de connaitre la position de la souris à tout moment et de déduire si elle entre ou quite le contrôle.. Sinon implementer IMessageFilter ou alors si tu veux faire une sorte de MousePreview sur le même principe que la propriète KeyPreview faut faire un hook ( un WH_MOUSE_LL ).
Commenter la réponse de Lutinore
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 6 janv. 2006 à 08:31
0
Merci
Moui à vrai dire je ne sais pas encore vraiment comment je vais résoudre ce problème mais je viendrai poster un message si j'y arrive...
Merci de votre aide en tout cas.


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
Commenter la réponse de cs_Bidou
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 6 janv. 2006 à 12:50
0
Merci
Concernant le hook je ne suis pas trop pour : inutile ici de recevoir les notifications pour l'intégralité de l'écran.

/*
coq
MVP Visual C#
*/
Commenter la réponse de cs_coq
cs_Bidou 5507 Messages postés dimanche 4 août 2002Date d'inscription 20 juin 2013 Dernière intervention - 6 janv. 2006 à 12:55
0
Merci
J'arriverai au bout de mes peines avec un IMessageFilter ou je me jette dans la gueule du loup?


<HR>

[Pub] http://www.csharpfr.com/auteurdetail.aspx?ID=13319 [\Pub]
C# forever
Commenter la réponse de cs_Bidou
cs_coq 6366 Messages postés samedi 1 juin 2002Date d'inscription 2 août 2014 Dernière intervention - 6 janv. 2006 à 13:34
0
Merci
Bon, je t'ai rapidement illustré le fond de ma pensée avec un petit exemple, ça sera plus clair :

public class ContainerLevelMouseEventsMessageFilter : IMessageFilter
{
public ContainerLevelMouseEventsMessageFilter(Control container)
{
if ( container == null )
throw new ArgumentNullException("container");


this._container = container;


this._container.Disposed += new EventHandler(_container_Disposed);
}


private Control _container = null;
private bool _isEntered = false;


private const int WM_MOUSEMOVE = 0x0200;


#region Membres de IMessageFilter


public bool PreFilterMessage(ref Message m)
{
if ( m.Msg == WM_MOUSEMOVE )
{
// détermine si la cible est notre contrôle ou est contenue par notre contrôle
Control ctrl = Control.FromHandle(m.HWnd); if ( ctrl !null && (ctrl this._container || this._container.Contains(ctrl)) )
{
if ( !this._isEntered )
{
// levée de MouseEnter
this.OnMouseEnter();


this._isEntered = true;
}


// récupération du point (en coordonnées du contrôle cible)
Point pt = new Point(m.LParam.ToInt32());


// conversion en coordonnée du contrôle
Point containerPoint = this._container.PointToClient(ctrl.PointToScreen(pt));


// levée de MouseMove
this.OnMouseMove(new MouseEventArgs(MouseButtons.None, 0, pt.X, pt.Y, 0));
}
else
{
// si la cible n'est pas un enfant, et que la sortie n'a pas encore été notifiée
if ( this._isEntered )
{
// levée de MouseLeave
this.OnMouseLeave();


this._isEntered = false;
}
}
}


return false;
}


#endregion


private void _container_Disposed(object sender, EventArgs e)
{
try
{
this._container = null;
Application.RemoveMessageFilter(this);
}
catch
{
}
}


public event MouseEventHandler MouseMove;
public event EventHandler MouseEnter;
public event EventHandler MouseLeave;


protected virtual void OnMouseMove(MouseEventArgs e)
{
if ( this.MouseMove != null )
this.MouseMove(this._container, e);
}


protected virtual void OnMouseLeave()
{
if ( this.MouseLeave != null )
this.MouseLeave(this._container, EventArgs.Empty);
}


protected virtual void OnMouseEnter()
{
if ( this.MouseEnter != null )
this.MouseEnter(this._container, EventArgs.Empty);
}
}

Utilisation :
ContainerLevelMouseEventsMessageFilter panelLevelEvents = new ContainerLevelMouseEventsMessageFilter(this.panel1);
Application.AddMessageFilter(panelLevelEvents);
panelLevelEvents.MouseEnter += new EventHandler(panelLevelEvents_MouseEnter);
panelLevelEvents.MouseLeave += new EventHandler(panelLevelEvents_MouseLeave);
panelLevelEvents.MouseMove += new MouseEventHandler(panelLevelEvents_MouseMove);

/*
coq
MVP Visual C#
*/
Commenter la réponse de cs_coq
Lutinore 3248 Messages postés lundi 25 avril 2005Date d'inscription 27 octobre 2012 Dernière intervention - 6 janv. 2006 à 16:48
0
Merci
Coq, comme d'hab ton code est complet et précis

Au passage je remarque que Control.Contains renvoie true pour les enfants des enfants, ça tombe bien..

J'imagine qu'il ne faut pas instancier ta classe dans le constructeur du contrôle ou alors en statique sinon on se retrouve avec plusieurs filtres ?

A propos des filtres sais tu à quoi sert les nouvelles fonctions Application.FilterMessage et Application.RegisterMessageLoop !?
Commenter la réponse de Lutinore

Vous n'êtes pas encore membre ?

inscrivez-vous, c'est gratuit et ça prend moins d'une minute !

Les membres obtiennent plus de réponses que les utilisateurs anonymes.

Le fait d'être membre vous permet d'avoir un suivi détaillé de vos demandes et codes sources.

Le fait d'être membre vous permet d'avoir des options supplémentaires.

Control et Mouse - page 2