2012-06-18 1 views
5

J'ai un composant pivotant qui comporte plusieurs sous-composants. Ce que je veux faire changer une étiquette si la souris est sur l'un de ces composants, puis le changer à quelque chose d'autre si la souris se déplace tous les composants. J'essaie de trouver un moyen plus efficace de le faire.Les écouteurs de la souris pivotante étant interceptés par des composants enfants

Actuellement, j'ai les auditeurs de la souris sur tous les composants de l'enfant qui ressemble à quelque chose comme:

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

Cela fonctionne, mais je me sens comme il devrait y avoir une meilleure façon de gérer cela en manipulant uniquement les événements mouseEntered et mouseExited sur le conteneur parent, mais comme les composants enfants interceptent ces événements, je ne suis pas sûr de savoir comment procéder (je n'ai pas forcément le contrôle sur les composants enfants donc je ne peux pas transférer les événements mouse à l'événement parent si je voulais).

+0

Pourquoi ne pas attribuer le même auditeur à tous les composants nécessaires. De cette façon, ils déclenchent tous exactement la même action. – Morfic

+0

pourriez-vous peut-être développer votre code pour montrer le probelm? Comme je ne comprends pas tout à fait le problème et votre solution 'souhaitée' –

+0

@Grove, si j'affecte le même écouteur à chaque composant, il y a une course potentielle selon que mouseEntered sur un composant se produit avant ou après mouseExited sur un autre. Disons que je suis sur component1 et que je déplace la souris vers component2. Si le mouseEntered Component2 est traité avant mouseExited Component1, le texte sera erroné. Je ne suis pas sûr s'il y a un ordre garanti à ces événements puisque le même mouvement de souris produirait le composant sortant1 et entrerait le composant 2. –

Répondre

7

Par exemple

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

Consultez les documents et les exemples pour la "vitre".
Cela devrait vous donner ce dont vous avez besoin: The Glass Pane

+0

Je pourrais utiliser le volet en verre pour toute la trame, mais le composant parent est juste un JPanel qui n'a pas de volet en verre. J'essayais de garder la solution localisée à juste ce composant parent afin qu'il puisse être réutilisé dans d'autres parties de l'application (dans lequel il peut ou peut ne pas être une vitre). –

+0

Pas sûr qu'il y ait beaucoup d'alternative. Je voudrais créer une classe de support pour installer et interagir avec une vitre. Le panneau peut ensuite instancier et interagir avec cette classe de support, qui va installer un volet de verre dans le JFrame parent pour capturer les événements pour les limites de votre panneau dans ce cadre. Ensuite, les événements pourraient être transmis à un auditeur de la souris nommé par le panel. Donc tout le travail acharné serait fait par la classe de support et le panneau obtiendrait juste les événements qu'il exige. – davidfrancis

+0

@Jeff Storey [peut-être pas vrai du tout] (http: // stackoverflow.com/a/9734016/714968) – mKorbel

1

Vous pouvez initialiser une seule instance de l'écouteur et ajouter cette instance à chaque composant. Comme ceci:

AMouseListener aMouseListener=new AMouseListener(); 

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

David, oui, je pourrais le faire. Mon souci était avec l'ordre des événements. Si le comportement mouseExited/mouseEntered peut être garanti, il s'agit d'un problème simple. –

+0

L'avez vous testé? Je sais que c'est évident, mais essayez-le sur les composants et voyez ce qu'il produit. –

+0

Bien sûr, mais même si cela fonctionne, je ne suis pas sûr de ce que (le cas échéant) les garanties sont faites sur la commande. –

Questions connexes