2010-10-10 3 views
4

Comment savoir si la souris se trouve sur une fenêtre de niveau supérieur? Par "over", je veux dire que le pointeur de la souris est dans le rectangle client de la fenêtre de premier niveau et il n'y a pas d'autre fenêtre de haut niveau sur ma fenêtre à l'emplacement du pointeur de la souris. En d'autres termes, si l'utilisateur cliquait sur l'événement, celui-ci serait envoyé à ma fenêtre de niveau supérieur (ou à l'une de ses fenêtres filles). J'écris en C# en utilisant Windows Forms, mais ça ne me dérange pas d'utiliser p/invoke pour faire des appels Win32.Comment puis-je savoir si la souris se trouve sur une fenêtre de niveau supérieur?

Répondre

3

Vous pouvez utiliser la fonction WinAPI WindowFromPoint. Sa signature C# est:

[DllImport("user32.dll")] 
static extern IntPtr WindowFromPoint(POINT Point); 

Notez que POINT ici ne sont pas les mêmes que System.Drawing.Point, mais PInvoke fournit a declaration for POINT that includes an implicit conversion between the two.

Si vous ne connaissez pas encore la position du curseur de la souris, GetCursorPos le trouve:

[DllImport("user32.dll")] 
static extern bool GetCursorPos(out POINT lpPoint); 

Cependant, le WinAPI appelle beaucoup de choses « fenêtres »: contrôles à l'intérieur d'une fenêtre sont également des « fenêtres ». Par conséquent, vous ne pouvez pas obtenir une fenêtre de niveau supérieur dans le sens intuitif (vous pouvez obtenir un bouton radio, panneau ou autre chose). Vous pouvez appliquer itérativement la fonction GetParent à marcher dans la hiérarchie GUI:

[DllImport("user32.dll", ExactSpelling=true, CharSet=CharSet.Auto)] 
public static extern IntPtr GetParent(IntPtr hWnd); 

Une fois que vous trouverez une fenêtre sans parent, cette fenêtre sera une fenêtre de niveau supérieur. Puisque le point que vous avez passé à l'origine appartient à un contrôle qui n'est pas couvert par une autre fenêtre, la fenêtre de niveau supérieur est nécessairement celle à laquelle le point appartient.

+0

La position du curseur peut être obtenue par 'Control.MousePosition'; La fenêtre parente peut être trouvée par un seul appel 'GetAncestor (hwnd, 2)' de 'user32.dll' (' GetParent' vérifie non seulement les parents mais aussi les propriétaires de fenêtres, ce qui peut ne pas être bon). – max

+0

Coredll.dll est uniquement approprié sur Windows Mobile. –

+0

@Hans: Merci, choisi le mauvais je suppose. Actualisé. – Timwi

2

Après avoir obtenu le handle de fenêtre, vous pouvez utiliser Control.FromHandle() pour obtenir une référence au contrôle. Ensuite, vérifiez la position relative de la souris pour voir si c'est la zone cliente du formulaire ou du contrôle. Comme ceci:

private void timer1_Tick(object sender, EventArgs e) { 
     var hdl = WindowFromPoint(Control.MousePosition); 
     var ctl = Control.FromHandle(hdl); 
     if (ctl != null) { 
      var rel = ctl.PointToClient(Control.MousePosition); 
      if (ctl.ClientRectangle.Contains(rel)) { 
       Console.WriteLine("Found {0}", ctl.Name); 
       return; 
      } 
     } 
     Console.WriteLine("No match"); 
    } 

    [System.Runtime.InteropServices.DllImport("user32.dll")] 
    private static extern IntPtr WindowFromPoint(Point loc); 
+0

Dans quelles circonstances la souris ne sera-t-elle pas dans la fenêtre retournée par WindowFromPoint? –

+0

@Daniel - à la demande de l'OP, lorsque la souris se trouve dans la zone non-client de la fenêtre. Comme la frontière et la légende d'un formulaire. –

+1

@Daniel, juste un supplément supplémentaire, vous pouvez utiliser 'GetWindowLongPtr()' directement pour vérifier s'il s'agit d'une fenêtre de niveau supérieur. Passez le paramètre 'GWL_EXSTYLE' au paramètre' nIndex', puis utilisez l'opération au niveau du bit sur le résultat de la fonction pour vérifier si elle contient la valeur 'WS_EX_TOPMOST'. – Vantomex

Questions connexes