Vous ne trouvez pas de réponse à votre problème ? Alors posez la question dans le forum. Souvenez-vous qu'il n'y a jamais de question bête, mais rester dans l'ignorance parce que l'on n'ose pas poser une question, ça c'est une erreur !

IMESSAGEFILTER : ÉVÉNEMENTS MOUSEMOVE / MOUSEENTER / MOUSELEAVE AU NIVEAU D'UN CONTRÔLE, SANS TENIR COMPTE DES CONTRÔLES ENFANTS


Information sur la source

Catégorie :.NET Source .NET ( DotNet ) Classé sous : imessagefilter, souris, mouseleave, mouseenter, mousemove Niveau : Débutant Date de création : 06/01/2006 Date de mise à jour : 04/05/2008 17:53:08 Vu / téléchargé: 12 715 / 490

Note :
9,83 / 10 - par 6 personnes
9,83 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

Commentaire sur cette source (13)
Ajouter un commentaire et/ou une note


Description

Cliquez pour voir la capture en taille normale
Les messages Windows, WM_MOUSE* dans notre cas, sont envoyés directement sur le contrôle concerné.
Si vous surchargez la méthode WndProc d'un contrôle "conteneur", vous ne verrez par conséquent pas les messages WM_MOUSEMOVE pour autant que le pointeur soit situé au dessus d'un contrôle enfant.
En gros les zones situées sous ces contrôles enfants sont des "zones mortes".
Pire, ce fonctionnement peut aussi être génant dans certains cas :
l'évènement MouseLeave sera par exemple déclenché si le curseur passe de la surface visible du contrôle conteneur à la surface d'un contrôle enfant.
Cette source est donc un exemple d'implémentation de l'interface IMessageFilter permettant d'avoir accès à ces évènements comme si il n'y avait aucun contrôle enfant à la surface du contrôle cible.
 

Source

  • /// <summary>
  • /// Implémentation de IMessageFilter permettant d'avoir accès à des events
  • /// MouseMove, MouseEnter et MouseLeaver au niveau du contrôle définis.
  • /// C'est-à-dire de recevoir l'event MouseMove même si le curseur se situe au dessus
  • /// d'un contrôle enfant.
  • /// </summary>
  • public class ContainerLevelMouseEventsMessageFilter : IMessageFilter
  • {
  • /// <summary>
  • /// Initialise une nouvelle instance de <see cref="ContainerLevelMouseEventsMessageFilter"/>.
  • /// </summary>
  • /// <param name="container">Contrôle pour lequel on veut les events.</param>
  • public ContainerLevelMouseEventsMessageFilter(Control container)
  • {
  • if ( container == null )
  • throw new ArgumentNullException("container");
  • this._container = container;
  • this._container.Disposed += new EventHandler(_container_Disposed);
  • }
  • /// <summary>
  • /// Contrôle pour lequel on veut les events.
  • /// </summary>
  • private Control _container = null;
  • /// <summary>
  • /// Permet de déterminer l'état de présence du pointeur sur le contrôle.
  • /// </summary>
  • private bool _isEntered = false;
  • /// <summary>
  • /// Constante WM_MOUSEMOVE. (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputmessages/wm_mousemove.asp)
  • /// Voir winuser.h du Platform SDK.
  • /// </summary>
  • private const int WM_MOUSEMOVE = 0x0200;
  • #region Events exposés
  • /// <summary>
  • /// Se produit lorsque le pointeur se déplace sur le contrôle.
  • /// </summary>
  • public event MouseEventHandler MouseMove;
  • /// <summary>
  • /// Se produit lorsque le pointeur se déplace pour la première fois sur le contrôle.
  • /// </summary>
  • public event EventHandler MouseEnter;
  • /// <summary>
  • /// Se produit lorsque le contrôle se déplace pour la première fois hors du contrôle.
  • /// </summary>
  • public event EventHandler MouseLeave;
  • /// <summary>
  • /// Déclenche l'évènement <see cref="MouseMove"/>.
  • /// </summary>
  • /// <param name="e"></param>
  • protected virtual void OnMouseMove(MouseEventArgs e)
  • {
  • if ( this.MouseMove != null )
  • this.MouseMove(this._container, e);
  • }
  • /// <summary>
  • /// Déclenche l'évènement <see cref="MouseLeave"/>.
  • /// </summary>
  • protected virtual void OnMouseLeave()
  • {
  • if ( this.MouseLeave != null )
  • this.MouseLeave(this._container, EventArgs.Empty);
  • }
  • /// <summary>
  • /// Déclenche l'évènement <see cref="MouseEnter"/>.
  • /// </summary>
  • protected virtual void OnMouseEnter()
  • {
  • if ( this.MouseEnter != null )
  • this.MouseEnter(this._container, EventArgs.Empty);
  • }
  • #endregion Events exposés
  • public bool PreFilterMessage(ref Message m)
  • {
  • // tout se joue sur le message WM_MOUSEMOVE
  • 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)) )
  • {
  • // si ce message WM_MOUSEMOVE est le premier que l'on obtient,
  • // nous devont déclencher l'évènement MouseEnter
  • if ( !this._isEntered )
  • {
  • // déclenchement 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, si nécessaire
  • Point containerPoint;
  • if ( ctrl != this._container )
  • containerPoint = this._container.PointToClient(ctrl.PointToScreen(pt));
  • else
  • containerPoint = pt;
  • // déclenchement 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,
  • // nous devons déclencher MouseLeave
  • if ( this._isEntered )
  • {
  • // déclenchement de MouseLeave
  • this.OnMouseLeave();
  • this._isEntered = false;
  • }
  • }
  • }
  • return false;
  • }
  • private void _container_Disposed(object sender, EventArgs e)
  • {
  • try
  • {
  • this._container = null;
  • Application.RemoveMessageFilter(this);
  • }
  • catch
  • {
  • }
  • }
  • }
  • // EXEMPLE D'UTILISATION
  • ContainerLevelMouseEventsMessageFilter panelLevelEvents = new ContainerLevelMouseEventsMessageFilter(this.panel);
  • Application.AddMessageFilter(panelLevelEvents);
  • panelLevelEvents.MouseEnter +=new EventHandler(panelLevelEvents_MouseEnter);
  • panelLevelEvents.MouseLeave +=new EventHandler(panelLevelEvents_MouseLeave);
    /// <summary>
    /// Implémentation de IMessageFilter permettant d'avoir accès à des events 
    /// MouseMove, MouseEnter et MouseLeaver au niveau du contrôle définis.
    /// C'est-à-dire de recevoir l'event MouseMove même si le curseur se situe au dessus
    /// d'un contrôle enfant.
    /// </summary>
    public class ContainerLevelMouseEventsMessageFilter : IMessageFilter
    {
        /// <summary>
        /// Initialise une nouvelle instance de <see cref="ContainerLevelMouseEventsMessageFilter"/>.
        /// </summary>
        /// <param name="container">Contrôle pour lequel on veut les events.</param>
        public ContainerLevelMouseEventsMessageFilter(Control container)
        {
            if ( container == null )
                throw new ArgumentNullException("container");

            this._container = container;

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

        /// <summary>
        /// Contrôle pour lequel on veut les events.
        /// </summary>
        private Control _container = null;
        /// <summary>
        /// Permet de déterminer l'état de présence du pointeur sur le contrôle.
        /// </summary>
        private bool _isEntered = false;

        /// <summary>
        /// Constante WM_MOUSEMOVE. (http://msdn.microsoft.com/library/default.asp?url=/library/en-us/winui/winui/windowsuserinterface/userinput/mouseinput/mouseinputreference/mouseinputmessages/wm_mousemove.asp)
        /// Voir winuser.h du Platform SDK.
        /// </summary>
        private const int WM_MOUSEMOVE  = 0x0200;

        #region Events exposés

        /// <summary>
        /// Se produit lorsque le pointeur se déplace sur le contrôle.
        /// </summary>
        public event MouseEventHandler MouseMove;
        /// <summary>
        /// Se produit lorsque le pointeur se déplace pour la première fois sur le contrôle.
        /// </summary>
        public event EventHandler MouseEnter;
        /// <summary>
        /// Se produit lorsque le contrôle se déplace pour la première fois hors du contrôle.
        /// </summary>
        public event EventHandler MouseLeave;

        /// <summary>
        /// Déclenche l'évènement <see cref="MouseMove"/>.
        /// </summary>
        /// <param name="e"></param>
        protected virtual void OnMouseMove(MouseEventArgs e)
        {
            if ( this.MouseMove != null )
                this.MouseMove(this._container, e);
        }

        /// <summary>
        /// Déclenche l'évènement <see cref="MouseLeave"/>.
        /// </summary>
        protected virtual void OnMouseLeave()
        {
            if ( this.MouseLeave != null )
                this.MouseLeave(this._container, EventArgs.Empty);
        }

        /// <summary>
        /// Déclenche l'évènement <see cref="MouseEnter"/>.
        /// </summary>
        protected virtual void OnMouseEnter()
        {
            if ( this.MouseEnter != null )
                this.MouseEnter(this._container, EventArgs.Empty);
        }

        #endregion Events exposés

        public bool PreFilterMessage(ref Message m)
        {
            // tout se joue sur le message WM_MOUSEMOVE
            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)) )
                {
                    // si ce message WM_MOUSEMOVE est le premier que l'on obtient, 
                    // nous devont déclencher l'évènement MouseEnter
                    if ( !this._isEntered )
                    {
                        // déclenchement 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, si nécessaire
                    Point containerPoint;
                    if ( ctrl != this._container )
                        containerPoint = this._container.PointToClient(ctrl.PointToScreen(pt));
                    else
                        containerPoint = pt;

                    // déclenchement 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, 
                    // nous devons déclencher MouseLeave
                    if ( this._isEntered )
                    {
                        // déclenchement de MouseLeave
                        this.OnMouseLeave();
                        this._isEntered = false;
                    }
                }
            }

            return false;
        }

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


// EXEMPLE D'UTILISATION
ContainerLevelMouseEventsMessageFilter panelLevelEvents = new ContainerLevelMouseEventsMessageFilter(this.panel);
Application.AddMessageFilter(panelLevelEvents);
panelLevelEvents.MouseEnter +=new EventHandler(panelLevelEvents_MouseEnter);
panelLevelEvents.MouseLeave +=new EventHandler(panelLevelEvents_MouseLeave);

Conclusion

WM_MOUSEMOVE : http://msdn.microsoft.com/en-us/library/ms645616.aspx

AddMessageFilter : http://msdn.microsoft.com/en-us/library/system.windows.forms.application.addmessagefilter.aspx

IMessageFilter : http://msdn.microsoft.com/en-us/library/system.windows.forms.imessagefilter.aspx

 

Fichier Zip

Pour les "Membres Club", vous pouvez télécharger directement un fichier contenu dans le zip sans télécharger le zip en entier !

Télécharger le zip

Historique

16 avril 2006 00:14:10 :
Ajout de l'exemple d'utilisation ;-)
04 mai 2008 17:53:09 :
Changement liens vers MSDN suite au shutdown complet de l'ancienne version (et des redirections).

Commentaires et avis

signaler à un administrateur
Commentaire de Bidou le 07/01/2006 02:48:07 administrateur CS

Excellent, encore merci :-)

signaler à un administrateur
Commentaire de badrbadr le 08/01/2006 19:19:40

super
j'avais super besoin de faire ca à un moment donné pour un de mes contrôles.
la solution que j'avais adopté est que les controles filles passent la position du curseur aux controles parents. J'ai aussi penser aux hooks mais c'est vraiment pas une bonne idée.
en tout cas, bravo
je vais me lancer dans l'analyse du code source ;)

signaler à un administrateur
Commentaire de oximoron le 22/01/2006 18:17:09

Merci beaucoup pour cette source, je vais aussi étudier ça de plus près.

signaler à un administrateur
Commentaire de philippe1796 le 15/05/2007 08:42:29

Cela correspond bien à un besoin mais il semble que cela ne fonctionne pas avec un ActiveX visuel sur le panel.

signaler à un administrateur
Commentaire de coq le 16/05/2007 21:47:04 administrateur CS

Oui, si le message destiné à l'ActiveX visuel ne transite pas par l'application, on ne peut pas faire l'interception.

signaler à un administrateur
Commentaire de nowox le 18/03/2008 20:16:00

La source est excellente merci. Ca illustre clairement comment utiliser IMessageFilter, ce que j'ignorais jusqu'ici.

J'ai cependant un petit soucis. Si j'ai effectivement besoin de capturer les évènements OnMouseMove, OnMouseLeave et OnMouseEnter, j'ai également besoin de capturer OnMouseDown et OnMouseUp. J'ai tenter de modifier le code mais je ne suis pas convaincu par ma modification qui ne semble fonctionner qu'à 50%...

signaler à un administrateur
Commentaire de coq le 22/03/2008 19:23:35 administrateur CS

Comment ça à 50% ?

signaler à un administrateur
Commentaire de Fredibulle le 27/02/2009 17:24:06

Ajout de cette ligne dans le constructeur, sinon ça ne fonctionne pas :
Application.AddMessageFilter(this);

Me suis permis d'améliorer un peu le code puisqu'il fonctionne uniquement sur une imbrication de premier niveau, nous pourrions très bien imaginer avoir plusieurs panel superposés les uns au dessus des autres avec des labels, etc...

donc cette ligne
[code]
if ( ctrl != null && (ctrl == this._container || this._container.Contains(ctrl)) )
[/code]
devient :
[code]
if ( ctrl != null && (ctrl == this._container || this.Contain(_container, ctrl)) )
[/code]
et la petite méthode récursive qui va bien :
[code]
protected bool Contain(Control parent, Control ctrl)
{
if (parent == ctrl)
{
return true;
}
foreach ( Control control in parent.Controls )
{
if ( this.Contain(control, ctrl) )
{
return true;
}
}
return false;
}
[/code]


signaler à un administrateur
Commentaire de Fredibulle le 27/02/2009 17:30:23

Oups, petite erreur et désolé pour les BBCode en trop sur ce premier post

if ( ctrl != null && (ctrl == this._container || this.Contain(_container, ctrl)) )

correction

if ( ctrl != null && this.Contain(_container, ctrl) )

Mais vous l'auriez vu ;)

signaler à un administrateur
Commentaire de Hurin le 07/06/2009 10:18:53 10/10

Je suis en train de le tester, et ça a l'air d'être exactement ce que je cherchais, merci beaucoup coq (et merci également à Fredibulle dont l'astuce est également utile) !

signaler à un administrateur
Commentaire de Hurin le 07/06/2009 10:28:42

Heu, je cherche également comment faire pour catcher un event sur MouseClick, et là, je ne trouve pas le message windows équivalent, si quelqu'un le connaissait, ça m'arrangerait :)
Merci !

signaler à un administrateur
Commentaire de coq le 07/06/2009 10:33:43 administrateur CS

Salut,

En fait c'est plutôt des couples :
- Bouton gauche : WM_LBUTTONDOWN et WM_LBUTTONUP
- Bouton droit : WM_RBUTTONDOWN et WM_RBUTTONUP
- ...

Voir aussi WM_LBUTTONDBLCLK, WM_RBUTTONDBLCLK, ...

signaler à un administrateur
Commentaire de Hurin le 07/06/2009 11:26:42

OK, je teste ça de suite, merci coq,
Bonne journée !

Ajouter un commentaire

Discussions en rapport avec ce code source dans le forum

Probléme BorderStyle, MouseEnter, MouseLeave dans PictureBox [ par rifi ] Voila, je veux créer un effet 3D chaque fois que mon controle PictureBox reçoit le focus (je modifie le borderstyle en Border3D) seulement lorsque la Evenements MouseEnter et MouseLeave [ par Souen29 ] Bonjour,Je suis sur le point de livrer une appli mais j'ai un petit souci de détailJe souhaite ecrire un message dans ma barre d'état suite au Interaction avec une Form sans prise de focus (Virtual Keyboard) [ par albundy91 ] Salut à tous,Je me permet de venir vers vous car me voilà confronté à un problème pour lequel je suis à cours d'idées et de capacité pour le résoudre [Souris et Clavier] [ par KqMii ] Bonjours, J'aimerais savoir comment je pourais par exemple quand j'appuis sur la touche F4 cela simule un clic souris et Quand j'appuis sur F3 Cela et Positionné la souris sur une liste deroulante [ par drcmomo ] Boonjour , J'ai un formulaire(page) dans lequel contient une liste deroulante(combobox). Je voudrais savoir si quelqu'un sait comment faire faire lors Detection du passage de la souris sur un gif sans prendre en compte la partie transparente [ par nonold ] Bonjour !Je m'explique, je charge une image gif dans une pictureBox et je souhaite faire changer le contour de l'image quand la souris la survole.Le p Effet player [ par watoubilly ] Bonjour,je souhaiterais faire une fenetre qui disparaisse comme windows media player lorsqu'un autre programme est en plein écran. Donc mon applicatio Mouse Leave Formulaire [ par AlexBoost ] SalutVoila j'ai un Formulaire avec des TextBox, des Buttons, webbrowser, etc ..Je voudrai exécuter des ligne de code lorsque la souris quitte le formu sprite=souris pb de coordonnée directX (c#) "draw2D" [ par 10demon10 ] bonjour à tous voila j'ai un petit bug avec mon apply et mon sprite qui est censé remplacer ma souris en effet il reste bloqué en haut a gauche de l'é Coordonée de Mouse dans picturebox [ par olibara ] BonjourComment puis-je recuperer les coordonnées XY de la souris sur un PictureBox dans une form ??J'utilise un Timer eventMais j'aimerais avoir la po


Nos sponsors

Sondage...

CalendriCode

Juillet 2009
LMMJVSD
  12345
6789101112
13141516171819
20212223242526
2728293031  

Consulter la suite du CalendriCode

Téléchargements

Logiciels à télécharger sur le même thème :

Comparez les prix Nouvelle version

Photothèque Nouveau !



Développement réalisé par Nicolas SOREL (Nix) avec l'aide de : Cyril DURAND et Emmanuel (EBArtSoft), Merci à Vincent pour ses précieux conseils
CodeS-SourceS.com© Toute reproduction même partielle est interdite sauf accord écrit du Webmaster
CodeS-SourceS.com© est une marque déposée tous droits réservés
Temps d'éxécution de la page : 0,655 sec

Google Coop CodeS-SourceS Google Coop CodeS-SourceS


Certaines images présentes sur le site (notament certains avatars) sont issues des collections IconShock, donc si vous souhaitez utiliser ces icons vous devez les acheter, ne les copiez pas et ne utilisez pas dans vos sites et applications sans les avoir commandé.