2012-06-18 20 views
5

Tengo un componente de giro que tiene varios subcomponentes. Lo que quiero hacer es cambiar una etiqueta si el mouse está sobre cualquiera de esos componentes, y luego cambiarlo a otra cosa si el mouse se mueve fuera de todos los componentes. Estoy tratando de encontrar una manera más eficiente de hacer esto.oyentes de ratón oscilante interceptados por componentes secundarios

Actualmente tengo oyentes ratón sobre todos los componentes hijos que miran algo como:

class AMouseListener extends MouseAdapter { 
    private boolean mouseOver; 
    mouseEntered(MouseEvent e) { mouseOver = true; updateLabel(); } 
    mouseExited(MouseEvent e) { mouseOver = false; updateLabel(); } 

    void updateLabel() { 
     String text = "not-over-any-components"; 
     // listeners are each of the listeners added to the child components 
     for (AMouseListener listener :listeners) { 
      if (listener.mouseOver) { 
      text = "over-a-component"; 
      break; 
      } 
     } 
    } 
} 

Esto funciona, pero siento que debe haber una mejor manera de manejar esto por el manejo única eventos mouseEntered y mouseExited en el contenedor principal, pero dado que los componentes secundarios interceptan estos eventos, no estoy seguro de cómo hacerlo (no necesariamente tengo control sobre los componentes secundarios, por lo que no puedo reenviar los eventos del mouse al evento principal) si quisiera).

+0

Por qué no asignar la misma escucha a todos los componentes necesarios. De esa forma, todos disparan exactamente la misma acción. – Morfic

+0

¿podría ampliar su código para mostrar el probelma? como no entiendo muy bien el probelma y su solución 'deseada' –

+0

@Grove, si asigno el mismo oyente a cada componente, existe una carrera potencial según si mouseEntered en un componente ocurre antes o después de mouseExited en otro. Digamos que estoy sobre componente1 y muevo el mouse hacia afuera al componente2. Si el mouseEntered Component2 se procesa antes que mouseExited Component1, el texto será incorrecto. No estoy seguro de si hay un orden garantizado para estos eventos ya que el mismo movimiento del mouse generaría la salida del componente1 y la entrada del componente2. –

Respuesta

7

Por ejemplo

enter image description here

enter image description here

import java.awt.Component; 
import java.awt.Dimension; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.*; 

public class TestMouseListener { 

    public static void main(String[] args) { 
     final JComboBox combo = new JComboBox(); 
     combo.setEditable(true); 
     for (int i = 0; i < 10; i++) { 
      combo.addItem(i); 
     } 
     final JLabel tip = new JLabel(); 
     tip.setPreferredSize(new Dimension(300, 20)); 
     JPanel panel = new JPanel(); 
     panel.add(combo); 
     panel.add(tip); 
     JFrame frame = new JFrame(); 
     frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE); 
     frame.add(panel); 
     frame.pack(); 
     frame.setVisible(true); 
     panel.addMouseListener(new MouseAdapter() { 

      @Override 
      public void mouseEntered(MouseEvent e) { 
       tip.setText("Outside combobox"); 
      } 

      @Override 
      public void mouseExited(MouseEvent e) { 
       Component c = SwingUtilities.getDeepestComponentAt(
        e.getComponent(), e.getX(), e.getY()); 
       // doesn't work if you move your mouse into the combobox popup 
       tip.setText(c != null && SwingUtilities.isDescendingFrom(
        c, combo) ? "Inside combo box" : "Outside combobox"); 
      } 
     }); 
    } 

    private TestMouseListener() { 
    } 
} 
2

Consulte los documentos y ejemplos para el "panel de vidrio".
Esto debería darle lo que necesita: The Glass Pane

+0

Podría usar el panel de vidrio para todo el marco, pero el componente principal es solo un JPanel que no tiene panel de vidrio. Intenté mantener la solución localizada solo en ese componente principal para que pueda volver a utilizarse en otras partes de la aplicación (en la que puede haber o no un panel de cristal). –

+0

No estoy seguro de que haya muchas alternativas. Crearía una clase de soporte para instalar e interactuar con un panel de vidrio. El panel puede entonces crear instancias e interactuar con esta clase de soporte, que instalará un panel de vidrio en el JFrame padre para capturar eventos para los límites de su panel dentro de ese marco. Luego, los eventos podrían reenviarse a un oyente de mouse nominado por el panel. Entonces todo el trabajo duro lo haría la clase de soporte y el panel obtendría los eventos que requiere. – davidfrancis

+0

@Jeff Storey [tal vez no sea verdad en absoluto] (http: // stackoverflow.com/a/9734016/714968) – mKorbel

1

Puede iniciar una única instancia del oyente y agregar esa instancia a cada componente. De esta manera:

AMouseListener aMouseListener=new AMouseListener(); 

for each(Component c:components) { 
caddMouseListener(aMouseListener); 
} 
+0

David, sí, podría hacer eso. Mi preocupación era con el orden de los eventos. Si se puede garantizar el comportamiento mouseExited/mouseEntered, entonces este es un problema simple. –

+0

¿Lo has probado? Sé que es obvio, pero pruébalo para ver los componentes y ver qué produce. –

+0

Claro, pero incluso si funciona, no estoy seguro de qué garantías (si las hay) sobre el pedido. –

Cuestiones relacionadas