2009-11-20 4 views
6

Ich habe ein Problem, bei dem Swing (in Java 1.6, Windows) scheint nicht mouseEntered und mouseExited Ereignisse wie ich es will auslösen. Ich habe eine Anwendung, bei der ich eine Anzahl von JPanels vertikal in einem JScrollPane gestapelt haben möchte, und dass sie mit einer anderen Farbe hervorgehoben werden sollen, wenn sich die Maus über ihnen befindet. Einfach genug Problem, aber wenn ich mit dem Mausrad blättern, verhält es sich nicht ganz.Swing wird mouseEntered/mouseEdited nach Mausrad-Ereignissen nicht korrekt auslösen?

Ich habe eine Beispielanwendung gemacht, um mein Problem zu veranschaulichen (Code unten gefunden). Die Bilder unten sind von dieser, nicht die "echte" Anwendung.

Wenn ich den Mauszeiger über den Rand eines Panels halte, wird er korrekt hervorgehoben. Wenn ich nun mit dem Mausrad nach unten scrolle, erwarte ich, dass der Cursor über Box B steht und die richtigen mouseEntered/mouseExited Events ausgelöst werden, so dass A weiß und B rot wird.

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

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

jedoch, die nicht zu passieren scheint.

Jetzt wird B hervorgehoben, wenn ich ein anderes Mausereignis triggere, sei es "move 1 pixel", "click a button" oder "scroll einen anderen Schritt". Wenn ich das weiß, könnte ich es vielleicht auf eine hackische Art und Weise lösen, aber ich würde lieber nicht, wenn es eine richtige Lösung gibt.

Also im Grunde was ich frage mich ist, ob dies als ein Bug in Swing betrachtet werden soll, oder mache ich nur Dinge falsch?

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

Die Einschränkungen gibt es aus einem bestimmten Grund. Ohne sie hätte SO ziemlich viele SPAM-Posts gehabt. Ich fügte die Bilder hinzu und entfernte Ihre Bemerkungen darüber, wie "die Regeln" hier "zurückgeblieben" sind. –

+0

Neben diesen Bemerkungen haben Sie eine ausgezeichnete Frage gestellt: klare Bilder, ein guter Codeschnipsel: gut gemacht. Ich bin kein Swing-Guru, aber ich werde es mir später ansehen (wenn es nicht schon beantwortet ist). +1 –

+0

Danke für die Bearbeitung.Es war ein bisschen frustrierend, zuerst mit dem Problem zu kämpfen, die Frage zu schreiben, das Snippet zu schreiben, gute Screenshots zu machen, sie auf einen Server hochzuladen und dann SO auf meinem Post zu haben, nur weil ich ein neuer Benutzer bin. Ich fühle mich jetzt besser. :-) – perp

Antwort

5

Dies scheint ein ähnliches Problem zu dem in Tooltips and Scrollpanes beschriebenen Problem zu sein. Das heißt, es werden keine Mausereignisse generiert, da sich die Maus nicht bewegt und das Ansichtsfenster verschoben wird. Ich bin nicht sicher, die genaue Lösung andere mit dem AdjustmentListener, um die Komponente an der Maus Position zu verfolgen. Jedes Mal, wenn Änderungen vorgenommen werden, können Sie ein mouseExited-Ereignis für das vorherige Bedienfeld und ein mouseEntered-Ereignis für das neue Bedienfeld auslösen.

3

Ich kann Ihren Code erhalten, um dies zuverlässig zu reproduzieren, aber nur wenn ich das Scrollen nicht ganz fertig bin. Auf meiner Maus gibt es zumindest eine Art "Fang", wenn das Mausrad das Scrollen beendet hat. Wenn ich sehr langsam blättern kann, kann ich es bewegen, aber es ändert nicht die Markierung, bis das Mausrad den "Fang" erreicht hat.

Wenn ich das tun, wird die Maus eingeben Nachricht auf dem vorherigen Panel empfangen (dasselbe Verhalten, das Sie sehen).

Wenn ich es anschaue, scrolle ich mit der Maus und es empfängt nicht wirklich die exited/eingegebene Ereignisse, es sei denn ich genug scrollen, um das Mausrad "fangen" zu lassen. Es ist möglich, dass Windows die Nachricht nicht an Java sendet, bis der "catch" passiert ... von meinen Tests, wie es aussieht.

Möglicherweise möchten Sie in die MouseWheelListener-Schnittstelle und die MouseInfo-Klasse suchen. Ich nehme an, Sie könnten die Radbewegung erkennen und dann herausfinden, wo Sie sich befinden mit MouseInfo.getPointerInfo(). GetLocation() und dann herausfinden, welche Komponente vorbei ist und die Hervorhebung ändern.

+0

Neugierig ... Ihr "Catch" könnte so grob sein, dass es die Maus ein wenig bewegt, wodurch ein Mausereignis ausgelöst wird. Sie könnten es mit der Unterseite der Maus versuchen, die in die Luft gezeigt wird, damit das Licht keine Traktion bekommen kann. Es kann auch sein, dass dein Scrollrad einen Button-3 nach unten verursacht oder etwas, was sonst nicht bemerkt würde. –

Verwandte Themen