2012-08-06 25 views
9

Necesito ayuda para comprender la propagación de eventos en Swing. Sé que cada evento es manejado por un solo componente. Por lo tanto, cuando tengo un panel outside con un panel secundario inside y agrego mouseListeners a ambos, se llamará al de inside. Eso es lindo y ese es el comportamiento esperado.MouseMotionListener en el componente secundario desactiva MouseListener en el componente principal

Pero no entiendo el comportamiento en la siguiente situación: inside registra un MouseMotionListener y outside registra un MouseListener. Espero que inside consuma todos MouseMotionEvents y outside para recibir MouseEvents, porque no hay ningún detector para MouseEvents normal en inside. Pero ese no es el caso, inside de alguna manera consume todos los eventos MouseEvents, no solo MouseMotionEvents.

El código siguiente ilustra el problema:

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class EventTest { 
public static void main(String... args) { 
    SwingUtilities.invokeLater(new Runnable(){ 
     @Override 
     public void run() { 
      JComponent inside = new JPanel(); 
      inside.setBackground(Color.red); 
      inside.setPreferredSize(new Dimension(200,200)); 
      MouseMotionListener mm = new MouseMotionListener() { 
       @Override 
       public void mouseDragged(MouseEvent arg0) { 
        System.err.println("dragged");      
       } 
       @Override 
       public void mouseMoved(MouseEvent arg0) { 
        System.err.println("moved"); 
       } 
      }; 
      // next line disables handling of mouse clicked events in outside 
      inside.addMouseMotionListener(mm); 

      JComponent outside = new JPanel(); 
      outside.add(inside); 
      outside.setPreferredSize(new Dimension(300,300)); 
      outside.addMouseListener(new MouseAdapter() { 
       public void mouseClicked(MouseEvent e) { 
        System.err.println("clicked"); 
       } 
      }); 

      JFrame frame = new JFrame(); 
      frame.add(outside); 
      frame.pack(); 
      frame.setVisible(true); 
     } 
    }); 
    } 
} 

pude solucionar el problema mediante el registro de un oyentes en inside para todos los eventos del componente padre podría estar interesado en y después de llamar dispatchEvent remitir el caso a la padre.

a) ¿alguien me puede indicar algunos documentos, donde se describe este comportamiento? Los javadocs de MouseEvent me hicieron pensar que mis expectativas eran correctas. Entonces, necesito una descripción diferente para entenderlo.

b) ¿hay alguna solución mejor que la que se ha descrito anteriormente?

Gracias, Kathrin

Editar: Todavía no está claro, ¿por qué oscilación se comporta de esta manera. Pero a medida que se ve, la única forma de hacer que las cosas funcionen es reenviar manualmente los eventos, lo haré.

+0

+1 para [sscce] (http://sscce.org/). – trashgod

Respuesta

8

a) Por design, los eventos del mouse de Java se "disparan" solo si no hay un detector de mouse en el componente secundario.

b) Puede adelantar eventos a otro componente, como se muestra here y más abajo.

import java.awt.*; 
import java.awt.event.*; 
import javax.swing.*; 

public class EventTest { 

    public static void main(String... args) { 
     SwingUtilities.invokeLater(new Runnable() { 

      @Override 
      public void run() { 
       final JComponent outside = new JPanel(); 
       JComponent inside = new JPanel(); 
       inside.setBackground(Color.red); 
       inside.setPreferredSize(new Dimension(200, 200)); 
       inside.addMouseMotionListener(new MouseAdapter() { 

        @Override 
        public void mouseDragged(MouseEvent e) { 
         System.err.println("dragged"); 
        } 

        @Override 
        public void mouseMoved(MouseEvent e) { 
         System.err.println("moved inside"); 
         outside.dispatchEvent(e); 
        } 
       }); 

       outside.add(inside); 
       outside.setPreferredSize(new Dimension(300, 300)); 
       outside.addMouseMotionListener(new MouseAdapter() { 

        @Override 
        public void mouseMoved(MouseEvent arg0) { 
         System.err.println("moved outside"); 
        } 
       }); 

       JFrame frame = new JFrame(); 
       frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 
       frame.add(outside); 
       frame.pack(); 
       frame.setVisible(true); 
      } 
     }); 
    } 
} 
1

muy similar a la respuesta de trashgod - se puede utilizar un MouseAdapter como su oyente movimiento y anularlo para reenviar los eventos que desea ser manejado por los padres. Esto solo debería agregar una cantidad mínima a tu código.

 MouseAdapter mm = new MouseAdapter() { 
      @Override 
      public void mouseDragged(MouseEvent arg0) { 
       System.err.println("dragged");      
      } 
      @Override 
      public void mouseMoved(MouseEvent arg0) { 
       System.err.println("moved"); 
      } 
      @Override 
      public void mouseClicked(MouseEvent e) { 
       outside.dispatchEvent(e); 
      } 
     }; 
     // For forwarding events 
     inside.addMouseListener(mm); 
     // For consuming events you care about 
     inside.addMouseMotionListener(mm); 

Yo tampoco pude encontrar ninguna forma de evitar el uso del método dispatchEvent(e). Creo que estás atrapado en esa ruta.

0

Esto funcionó para mí:

Ellipse2D mCircle = new Ellipse2D.Double(x,y,size,size); 

    void PassMouseEvent(MouseEvent e) { 
    getParent().dispatchEvent(e); 
    } 

    public void mousePressed(MouseEvent arg0) { 
    if(mCircle.contains(arg0.getX(), arg0.getY())) { 
     // Do stuff if we click on this object 
    } else { 
     // Pass to the underlying object to deal with the mouse event 
     PassMouseEvent(arg0); 
    } 
    } 
Cuestiones relacionadas