begin process at 2008 07 21 03:35:59
1 213 565 membres
33 nouveaux aujourd'hui
14 167 membres club

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é: 10 970 / 442

Note :
9,8 / 10 - par 5 personnes
9,80 / 10

  • 1

  • 2

  • 3

  • 4

  • 5

  • 6

  • 7

  • 8

  • 9

  • 10

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


Description

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
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

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).
  • 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% ?

Ajouter un commentaire

Pub



Appels d'offres

Dessins techniques
Budget : 60€
Animation Flash - Doma...
Budget : 370€
Application flash medi...
Budget : 1 000€

CalendriCode

Juillet 2008
LMMJVSD
 123456
78910111213
14151617181920
21222324252627
28293031   

Téléchargements

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

Boutique

Boutique de goodies CodeS-SourceS