2010-03-15 17 views
12

Zasadniczo istnieje JPanel, o którym chcę wiedzieć, kiedy mysz wchodzi w obszar JPanel i opuszcza obszar JPanel. Dodałem więc słuchacza myszy, ale jeśli w JPanelu znajdują się komponenty, a myszka przejdzie nad jednym z nich, zostanie to wykryte jako wyjście na JPanel, nawet jeśli komponent znajduje się na JPanelu. Zastanawiam się, czy ktoś nie wie, jak rozwiązać ten problem, nie robiąc czegoś takiego, jak dodawanie słuchaczy do wszystkich komponentów w JPanelu?Wykrywanie zdarzeń wejścia/wyjścia myszy w dowolnym miejscu na JPanel

+0

Odpowiedzi na to pytanie dotyczą Twojego problemu: http://stackoverflow.com/questions/1882055/java-swing-change-background-color-on-mouse-over – Ash

Odpowiedz

0

Jeśli chcesz, aby wszystkie zdarzenia były wysyłane do okna najwyższego poziomu, możesz dodać detektor do tafli szkła JFrame. Zobacz: http://java.sun.com/j2se/1.4.2/docs/api/javax/swing/RootPaneContainer.html#getGlassPane%28%29

+0

Pytanie dotyczyło JPanel, a nie JFrame. Możesz odpowiedzieć na to pytanie, ale tylko częściowo, więc odpowiedź nie jest odpowiednia dla początkującego. PS: nawet w 2010 roku, myślę, że jest lepszy link do dokumentów w Javie 1.6. – PhiLho

7

Oto jeden ze sposobów, aby to zrobić dla składnika, który może zawierać inne składniki:

  1. Dodaj globalną detektor zdarzeń AWT, aby wszystkie zdarzenia myszy. Na przykład:

    Toolkit.getDefaultToolkit().addAWTEventListener( 
        new TargetedMouseHandler(panel), AWTEvent.MOUSE_EVENT_MASK); 
    
  2. Wdrożenie TargetedMouseHandler ignorować zdarzeń, które nie są pozyskiwane przez centralę lub przez jedno z dzieci na panelu (można użyć SwingUtilities.isDescendingFrom przetestować na ten temat).

  3. Śledź, czy mysz znajduje się już poza granicami twojego panelu. Kiedy otrzymasz zdarzenie MouseEvent.MOUSE_ENTERED w swoim panelu lub jednym z jego elementów podrzędnych, ustaw flagę na true.

  4. Po uzyskaniu zdarzenia MouseEvent.MOUSE_EXITED, zresetuj tylko flagę, jeśli punkt w MouseEvent znajduje się poza granicami panelu docelowego. SwingUtilities.convertPoint i Component.getBounds().contains() będzie przydatna tutaj.

+0

Próbowałem zaimplementować twój pomysł (mieć globalny handler kliknięciem prawym przyciskiem myszy (menu kontekstowe) na panelu z komponentami), ale odkryłem, że jest naprawdę globalny, tj. na poziomie całej aplikacji, co może być denerwujące z wewnętrznymi ramkami, tak jak mamy, i musimy usunąć program obsługi podczas zamykania odpowiedniej wewnętrznej ramki. Wciąż ciekawa i pouczająca odpowiedź, która może być dostosowana do prostszych przypadków. – PhiLho

4

Oto przykładowy kod implementujący rozwiązanie Asha. Dla mnie JFrame nie wykrył poprawnie wszystkich zdarzeń wyjściowych, ale zrobił to wewnętrzny JPanel, więc przekazałem dwa komponenty - jeden do testowania potomków i jeden do testowania granicy.

Toolkit.getDefaultToolkit().addAWTEventListener(
     new TargetedMouseHandler(this, this.jPanel), 
     AWTEvent.MOUSE_EVENT_MASK); 
} 

public class TargetedMouseHandler implements AWTEventListener 
{ 

    private Component parent; 
    private Component innerBound; 
    private boolean hasExited = true; 

    public TargetedMouseHandler(Component p, Component p2) 
    { 
     parent = p; 
     innerBound = p2; 
    } 

    @Override 
    public void eventDispatched(AWTEvent e) 
    { 
     if (e instanceof MouseEvent) 
     { 
      if (SwingUtilities.isDescendingFrom(
       (Component) e.getSource(), parent)) 
      { 
       MouseEvent m = (MouseEvent) e; 
       if (m.getID() == MouseEvent.MOUSE_ENTERED) 
       { 
        if (hasExited) 
        { 
         System.out.println("Entered"); 
         hasExited = false; 
        } 
       } else if (m.getID() == MouseEvent.MOUSE_EXITED) 
       { 
        Point p = SwingUtilities.convertPoint(
         (Component) e.getSource(), 
         m.getPoint(), 
         innerBound); 
        if (!innerBound.getBounds().contains(p)) 
        { 
         System.out.println("Exited"); 
         hasExited = true; 
        } 
       } 
      } 
     } 
    } 
} 
8

Jest bardzo proste rozwiązanie tego problemu, które mogą działać:

public class MyJPanel implements MouseListener { 

    public void mouseExited(MouseEvent e) { 
     java.awt.Point p = new java.awt.Point(e.getLocationOnScreen()); 
     SwingUtilities.convertPointFromScreen(p, e.getComponent()); 
     if(e.getComponent().contains(p)) {return;} 
     ...//the rest of your code 
    } 

    ... 
} 

ten sposób można po prostu zignorować to wydarzenie mouseExited gdy występuje na elemencie dziecięcej.

Powiązane problemy