2010-03-15 8 views
12

Básicamente hay un JPanel en el que quiero saber cuando el mouse ingresa al área de JPanel y sale del área de JPanel. Así que agregué un detector de mouse, pero si hay componentes en el JPanel y el mouse pasa sobre uno de ellos, se detecta como una salida en el JPanel, aunque el componente esté en el JPanel. Me preguntaba si alguien sabe alguna forma de resolver este problema sin hacer algo como agregar oyentes en todos los componentes en el JPanel.Detectando eventos de entrada/salida de mouse en cualquier parte de JPanel

+0

Las respuestas en esta pregunta son aplicables a su problema: http://stackoverflow.com/questions/1882055/java-swing-change-background-color-on-mouse-over – Ash

Respuesta

7

Aquí es una manera de hacerlo para un componente que puede contener otros componentes:

  1. Añadir un detector de eventos AWT mundial para obtener todos los eventos del ratón. Por ejemplo:

    Toolkit.getDefaultToolkit().addAWTEventListener( 
        new TargetedMouseHandler(panel), AWTEvent.MOUSE_EVENT_MASK); 
    
  2. implementar el TargetedMouseHandler ignorar eventos que no son de origen por el panel o por uno de los niños del panel (que puede utilizar para probar SwingUtilities.isDescendingFrom para esto).

  3. Mantenga un registro de si el mouse ya está dentro de los límites de su panel. Cuando obtiene un evento MouseEvent.MOUSE_ENTERED en su panel o uno de sus elementos secundarios, establezca un indicador en verdadero.

  4. Cuando obtiene un evento MouseEvent.MOUSE_EXITED, solo restablezca el indicador si el punto en el MouseEvent está fuera de los límites de su panel de destino. SwingUtilities.convertPoint y Component.getBounds().contains() serán útiles aquí.

+0

Intenté implementar tu idea (para tener un controlador global con el botón derecho del ratón (menú contextual) en un panel con componentes), pero descubrí que es realmente global, es decir. en todo el nivel de la aplicación, lo que podría ser molesto con los marcos internos como lo tenemos, y debemos eliminar el controlador al cerrar el marco interno correspondiente. Sigue siendo una respuesta interesante e informativa, que puede ser adecuada para casos más simples. – PhiLho

4

Este es un código de ejemplo que implementa la solución de Ash. Para mí, el JFrame no detectó todos los eventos de salida correctamente, pero sí un JPanel interno, así que pasé dos componentes: uno para probar descendientes y otro para probar el límite.

Toolkit.getDefaultToolkit().addAWTEventListener(
     new TargetedMouseHandler(this, this.jPanel), 
     AWTEvent.MOUSE_EVENT_MASK); 
} 

public class TargetedMouseHandler implements AWTEventListener 
{ 

    private Component parent; 
    private Component innerBound; 
    private boolean hasExited = true; 

    public TargetedMouseHandler(Component p, Component p2) 
    { 
     parent = p; 
     innerBound = p2; 
    } 

    @Override 
    public void eventDispatched(AWTEvent e) 
    { 
     if (e instanceof MouseEvent) 
     { 
      if (SwingUtilities.isDescendingFrom(
       (Component) e.getSource(), parent)) 
      { 
       MouseEvent m = (MouseEvent) e; 
       if (m.getID() == MouseEvent.MOUSE_ENTERED) 
       { 
        if (hasExited) 
        { 
         System.out.println("Entered"); 
         hasExited = false; 
        } 
       } else if (m.getID() == MouseEvent.MOUSE_EXITED) 
       { 
        Point p = SwingUtilities.convertPoint(
         (Component) e.getSource(), 
         m.getPoint(), 
         innerBound); 
        if (!innerBound.getBounds().contains(p)) 
        { 
         System.out.println("Exited"); 
         hasExited = true; 
        } 
       } 
      } 
     } 
    } 
} 
8

hay una solución muy fácil para este problema que puede trabajar:

public class MyJPanel implements MouseListener { 

    public void mouseExited(MouseEvent e) { 
     java.awt.Point p = new java.awt.Point(e.getLocationOnScreen()); 
     SwingUtilities.convertPointFromScreen(p, e.getComponent()); 
     if(e.getComponent().contains(p)) {return;} 
     ...//the rest of your code 
    } 

    ... 
} 

De esta manera usted solo ignora el evento mouseExited cuando se presenta en un elemento secundario.

Cuestiones relacionadas