2012-06-18 12 views
5

Mam element swing, który ma kilka komponentów podrzędnych. Co chcę zrobić zmienić niektóre etykiety, jeśli mysz jest nad jednym z tych składników, a następnie zmienić go na coś innego, jeśli mysz porusza się wszystkie składniki. Próbuję znaleźć bardziej skuteczny sposób na zrobienie tego.swingers słuchacze są przechwytywane przez elementy potomne

Obecnie mam słuchaczy myszy nad wszystkich elementów podrzędnych, które wyglądają mniej więcej tak:

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; 
      } 
     } 
    } 
} 

To działa, ale czuję się jak nie powinno być lepszym sposobem obsługi to tylko przez obsługę mouseEntered i mouseExited wydarzenia w kontenerze nadrzędnym, ale ponieważ komponenty potomne przechwytują te zdarzenia, nie jestem pewien, jak to zrobić (niekoniecznie mam kontrolę nad komponentami potomnymi, więc nie mogę przekazać zdarzeń myszy do zdarzenia nadrzędnego jeśli chciałem).

+0

Dlaczego nie przydzielić tego samego słuchacza do wszystkich niezbędnych składników. W ten sposób wszyscy uruchamiają dokładnie tę samą akcję. – Morfic

+0

Czy mógłbyś rozwinąć swój kod, aby pokazać probelm? ponieważ nie bardzo rozumiem probelm i twoje "pożądane" rozwiązanie –

+0

@Grove, jeśli przypiszę tego samego słuchacza do każdego komponentu, istnieje potencjalny wyścig w zależności od tego, czy mouseEntered na jednym komponencie występuje przed czy po mouseExited na innym. Załóżmy, że mam ponad komponent1 i przenoszę myszkę na komponent2. Jeśli składnik MouseEntered Component2 zostanie przetworzony przed komponentem MouseExited Component1, tekst będzie niepoprawny. Nie jestem pewien, czy istnieje zagwarantowana kolejność tych zdarzeń, ponieważ ten sam ruch myszy wygenerowałby wyjście z komponentu1 i wprowadzenie komponentu2. –

Odpowiedz

7

Na przykład

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

Zapoznaj się z dokumentami i przykładami "szklanej tafli".
To powinno dać ci to, czego potrzebujesz: The Glass Pane

+0

Mogę użyć tafli szkła przez całą ramkę, ale elementem macierzystym jest tylko JPanel, który nie ma tafli szkła. Starałem się, aby rozwiązanie było zlokalizowane tylko dla tego komponentu nadrzędnego, aby mogło być ponownie wykorzystane w innych częściach aplikacji (w której może być lub nie jest tafla szkła). –

+0

Nie wiem, czy jest dużo alternatywy. Stworzyłem klasę wsparcia, aby zainstalować i współpracować z taflą szkła. Panel może następnie utworzyć instancję i interakcję z tą klasą wsparcia, która zainstaluje szklany panel w macierzystej ramce JFrame w celu przechwytywania zdarzeń dla granic twojego panelu w tej ramce. Następnie zdarzenia mogą być przekazywane dalej do odbiornika myszy wyznaczonego przez panel. Więc cała ciężka praca zostanie wykonana przez klasę wsparcia, a panel po prostu dostarczy wymaganych wydarzeń. – davidfrancis

+0

@Jeff Storey [może w ogóle nie jest prawdą] (http: // stackoverflow.com/a/9734016/714968) – mKorbel

1

Możesz zainicjować pojedyncze wystąpienie detektora i dodać tę instancję do każdego komponentu. Jak to:

AMouseListener aMouseListener=new AMouseListener(); 

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

David, tak, mógłbym to zrobić. Moje zainteresowanie dotyczyło uporządkowania wydarzeń. Jeśli można zagwarantować zachowanie mouseExited/mouseEntered, jest to prosty problem. –

+0

Przetestowałeś to? Wiem, że jest to oczywiste, ale spróbuj przejść przez komponenty i zobaczyć, co produkuje. –

+0

Oczywiście, ale nawet jeśli zadziała, nie jestem pewien, jakie (jeśli w ogóle) są gwarancje dotyczące zamówienia. –

Powiązane problemy