2009-11-20 14 views
6

Ho un problema in cui Swing (in Java 1.6, Windows) non sembra attivare gli eventi mouseEntered e mouseExited nel modo in cui lo desidero. Ho un'applicazione in cui desidero avere un numero di JPanel impilati verticalmente in un JScrollPane e che dovrebbero essere evidenziati con un colore diverso quando il mouse è sopra di loro. Un problema abbastanza semplice, ma ogni volta che si scorre usando la rotellina del mouse, non si comporta in modo adeguato.L'oscillazione non attiverà mouseEntered/mouseExited correttamente dopo gli eventi della rotellina del mouse?

Ho creato un'applicazione di esempio per illustrare il mio problema (codice trovato di seguito). Le immagini qui sotto sono da quella, non l'applicazione "reale".

Quando tengo il cursore del mouse sopra il bordo di un pannello, è evidenziato correttamente. Ora, quando uso la rotellina del mouse per scorrere verso il basso, mi aspetto che il cursore si trovi sopra la casella B e che gli eventi mouseEntered/mouseExited appropriati vengano attivati ​​in modo che A diventi bianco e B diventi rosso.

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

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

Tuttavia, ciò non sembra accadere.

Ora, B viene evidenziato se si attiva un altro evento del mouse, sia "sposta 1 pixel", "fai clic su un pulsante" o "scorri un altro passaggio". Sapendo questo, potrei forse risolverlo in un modo hacker, ma preferirei non se c'è una soluzione adeguata.

Quindi in pratica quello che mi chiedo è se questo deve essere considerato un bug in Swing, o sto semplicemente facendo le cose sbagliate?

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

Le restrizioni ci sono per un motivo. Senza di esso, SO avrebbe avuto un bel po 'di messaggi SPAM. Ho aggiunto le immagini e rimosso le tue osservazioni su come "ritardato" le regole qui sono. –

+0

Oltre a queste osservazioni, hai posto una domanda eccellente: immagini chiare, un buon frammento di codice: ben fatto. Non sono un guru dello Swing, ma lo vedrò più avanti (se non è già stato risposto). +1 –

+0

Grazie per la modifica.E 'stato un po' frustrante per prima cosa lottare con il problema, scrivere la domanda, scrivere lo snippet, prendere buoni screenshot, caricarli su un server e poi avere SO barf al mio post solo perché sono un nuovo utente. Mi sento meglio ora. :-) – perp

risposta

5

Questo sembra un problema simile a quello descritto in Tooltips and Scrollpanes. Cioè, non vengono generati eventi del mouse perché il mouse stesso non si muove, la finestra si sposta. Non sono sicuro che la soluzione esatta altro usi il AdjustmentListener per tracciare il componente nella posizione del mouse. Ogni volta che si apportano modifiche, è possibile attivare un evento mouseExited nel pannello precedente e un evento mouse inserito nel nuovo pannello.

3

posso ottenere il codice per riprodurre questo modo affidabile, ma solo quando non ho ben finire lo scorrimento. Almeno sul mio mouse c'è una specie di "presa" quando la rotellina del mouse termina lo scorrimento. Se scorro molto lentamente posso farlo muovere ma non cambia il momento saliente finché la rotella del mouse non ha raggiunto il "fermo".

Quando si esegue questa operazione, il messaggio di immissione del mouse viene ricevuto sul pannello precedente (lo stesso comportamento visualizzato).

Guardandolo, faccio scorrere il mouse e in realtà non riceve gli eventi entrati/inseriti a meno che non scorra abbastanza da far "catturare" la rotellina del mouse. È possibile che Windows non invii il messaggio a Java fino a quando non si verifica il "catch" ... dai miei test che è quello che sembra.

Si potrebbe voler esaminare l'interfaccia MouseWheelListener e la classe MouseInfo. Immagino che potresti essere in grado di rilevare il movimento della ruota e quindi capire dove ti trovi con MouseInfo.getPointerInfo(). GetLocation() e quindi capire quale componente sei finito e modificare l'evidenziazione.

+0

Curioso ... Il tuo "Catch" potrebbe essere abbastanza approssimativo da spostare leggermente il mouse, causando un evento del mouse. Potresti provarlo con la parte inferiore del mouse puntata in aria in modo che la luce non possa ottenere alcuna trazione. Potrebbe anche darsi che la rotella di scorrimento causi un pulsante-3 in basso o qualcosa del genere, qualcosa che altrimenti non verrebbe notato. –

Problemi correlati