2009-11-20 21 views
6

Tengo un problema donde Swing (en Java 1.6, Windows) no parece desencadenar eventos mouseEntered y mouseExited de la manera que yo quiero. Tengo una aplicación donde deseo tener varios JPanels apilados verticalmente en un JScrollPane, y que deben resaltarse con un color diferente cuando el mouse está sobre ellos. Problema bastante simple, pero cada vez que me desplazo con la rueda del mouse, no se comporta del todo.Swing no activará mouseEntered/mouseExited correctamente después de los eventos de la rueda del mouse?

He hecho una aplicación de muestra para ilustrar mi problema (código que se encuentra a continuación). Las imágenes a continuación son de esa, no de la aplicación "real".

Cuando sostengo el cursor del mouse sobre el borde de un panel, se resalta correctamente. Ahora, cuando uso la rueda del mouse para desplazarme hacia abajo, espero que el cursor esté sobre el recuadro B y que los eventos mouseEntered/mouseExited correctos se activen para que A se convierta en blanco y B en rojo.

alt text http://perp.se/so/1.png

alt text http://perp.se/so/2.png

Sin embargo, eso no parece suceder.

Ahora, B se resalta si disparo otro evento de mouse, ya sea "mover 1 píxel", "hacer clic en un botón" o "desplazar otro paso". Sabiendo esto, quizás podría resolverlo de una manera hackosa, pero preferiría no hacerlo si hay una solución adecuada.

Así que, básicamente, lo que me pregunto es si esto se debe considerar como un error en Swing, ¿o simplemente estoy haciendo las cosas mal?

import java.awt.Color; 
import java.awt.Dimension; 
import java.awt.Font; 
import java.awt.GridBagConstraints; 
import java.awt.GridBagLayout; 
import java.awt.GridLayout; 
import java.awt.Insets; 
import java.awt.event.MouseAdapter; 
import java.awt.event.MouseEvent; 
import javax.swing.BorderFactory; 
import javax.swing.JFrame; 
import javax.swing.JLabel; 
import javax.swing.JPanel; 
import javax.swing.JScrollPane; 
import javax.swing.SwingConstants; 
import javax.swing.SwingUtilities; 

public class ScrollTest extends JFrame { 

    public static class LetterPanel extends JPanel { 

     private static final Font BIG_FONT = new Font(Font.MONOSPACED, Font.BOLD, 24); 

     public LetterPanel(String text) { 
      setBackground(Color.WHITE); 
      setBorder(BorderFactory.createLineBorder(Color.BLACK)); 

      addMouseListener(new MouseAdapter() { 

       @Override 
       public void mouseEntered(MouseEvent e) { 
        setBackground(Color.RED); 
       } 

       @Override 
       public void mouseExited(MouseEvent e) { 
        setBackground(Color.WHITE); 
       } 
      }); 

      setLayout(new GridLayout(1, 1)); 
      setPreferredSize(new Dimension(-1, 50)); 

      JLabel label = new JLabel(text, SwingConstants.CENTER); 
      label.setFont(BIG_FONT); 
      add(label); 
     } 
    } 

    public ScrollTest() { 
     setLayout(new GridLayout(1, 1)); 
     setSize(400, 400); 

     JPanel base = new JPanel(); 

     JScrollPane jsp = new JScrollPane(base); 
     jsp.getVerticalScrollBar().setUnitIncrement(16); 
     add(jsp); 

     base.setLayout(new GridBagLayout()); 
     GridBagConstraints gbc = new GridBagConstraints(); 
     gbc.gridx = 0; 
     gbc.gridy = 0; 
     gbc.gridheight = 1; 
     gbc.gridwidth = 1; 
     gbc.fill = GridBagConstraints.HORIZONTAL; 
     gbc.insets = new Insets(0, 0, 10, 0); 
     gbc.weightx = 1.0; 

     for (char c = 'A'; c <= 'Z'; c++) { 
      base.add(new LetterPanel(String.valueOf(c)), gbc); 
      gbc.gridy++; 
     } 
    } 

    public static void main(String[] args) { 
     final JFrame f = new ScrollTest(); 
     f.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE); 

     SwingUtilities.invokeLater(new Runnable() { 

      public void run() { 
       f.setVisible(true); 
      } 
     }); 
    } 
}
+1

Las restricciones están ahí por algún motivo. Sin él, SO habría tenido bastante SPAM-posts. Agregué las imágenes y eliminé sus comentarios acerca de cómo "retardaron" las reglas aquí. –

+0

Además de esas observaciones, ha hecho una excelente pregunta: imágenes claras, un buen fragmento de código: bien hecho. No soy un gurú de Swing, pero lo echaré un vistazo más adelante (si ya no está respondido). +1 –

+0

Gracias por la edición.Fue un poco frustrante luchar primero con el problema, escribir la pregunta, escribir el fragmento, tomar buenas capturas de pantalla, subirlas a un servidor y luego tener SO Barf en mi publicación solo porque soy un nuevo usuario. Me siento mejor ahora. :-) – perp

Respuesta

5

Parece un problema similar al descrito en Tooltips and Scrollpanes. Es decir, no se generan eventos de mouse porque el mouse en sí no se mueve, la ventana gráfica se mueve. No estoy seguro de cuál es la solución exacta que usa AdjustmentListener para rastrear el componente en la ubicación del mouse. Cada vez que realice cambios, puede activar un evento mouseExited en el panel anterior y un evento mouseEntered en el nuevo panel.

3

Puedo obtener su código para reproducir esto de manera confiable, pero solo cuando no termine el desplazamiento. En mi mouse, al menos, hay una especie de "atrapar" cuando la rueda del mouse termina de desplazarse. Si me desplazo muy despacio, puedo hacer que se mueva, pero no cambia el resaltado hasta que la rueda del mouse haya alcanzado el "catch".

Cuando hago eso, el mensaje ingresado en el mouse se recibe en el panel anterior (el mismo comportamiento que está viendo).

Al mirarlo, desplazo el mouse y en realidad no recibe los eventos salidos/ingresados ​​a menos que me mueva lo suficiente para que la rueda del mouse se "atrape". Es posible que Windows no envíe el mensaje a Java hasta que ocurra la "captura" ... de mi prueba, que es lo que parece.

Es posible que desee examinar la interfaz MouseWheelListener y la clase MouseInfo. Supongo que es posible que pueda detectar el movimiento de la rueda y luego averiguar dónde se encuentra con MouseInfo.getPointerInfo(). GetLocation() y luego averiguar qué componente es usted y cambiar el resaltado.

+0

Curioso ... Su "Captura" podría ser lo suficientemente difícil como para mover el mouse un poco, lo que hace que se produzca un evento de mouse. Puede intentarlo con la punta del mouse apuntando al aire para que la luz no pueda obtener tracción. También podría ser que su rueda de desplazamiento provoque un botón-3 hacia abajo o algo así, algo que de otra manera no se notaría. –

Cuestiones relacionadas