web-dev-qa-db-fra.com

Obtenir un composant Swing par son nom

J'ai dans une variable JFrame certains composants que je veux que Fasse référence à une autre JFrame et je veux que Les obtiennent par leur nom et non N'utilisent/ne définissent pas de méthode publique pour chacun.

Existe-t-il un moyen, pour Swing, d’obtenir une référence de composant par son nom comme faire C #?

par exemple. form.Controls["text"]

Merci

14
xdevel2000

Je sais que c'est une vieille question, mais je me suis retrouvé à la poser tout à l'heure. Je voulais un moyen facile d'obtenir les composants par leur nom. Je n'avais donc pas besoin d'écrire du code compliqué à chaque fois pour accéder à différents composants. Par exemple, un JButton accède au texte dans un champ de texte ou à une sélection dans une liste.

La solution la plus simple consiste à transformer toutes les variables de composant en variables de classe afin de pouvoir y accéder n'importe où. Cependant, tout le monde ne veut pas le faire, et certains (comme moi) utilisent des éditeurs d’interface graphique qui ne génèrent pas les composants en tant que variables de classe.

Ma solution est simple, j'aimerais réfléchir, et ne viole pas vraiment les normes de programmation, autant que je sache (faisant référence à ce que voulait faire Fortran). Il offre un moyen simple et direct d’accéder aux composants par leur nom.

  1. Créez une variable de classe Map. Vous aurez besoin d'importer HashMap au moins . J'ai nommé mine composantMap pour plus de simplicité.

    private HashMap componentMap;
    
  2. Ajoutez tous vos composants au cadre comme d'habitude.

    initialize() {
        //add your components and be sure
        //to name them.
        ...
        //after adding all the components,
        //call this method we're about to create.
        createComponentMap();
    }
    
  3. Définissez les deux méthodes suivantes dans votre classe. Vous devrez importer Component si vous n'avez pas déjà:

    private void createComponentMap() {
            componentMap = new HashMap<String,Component>();
            Component[] components = yourForm.getContentPane().getComponents();
            for (int i=0; i < components.length; i++) {
                    componentMap.put(components[i].getName(), components[i]);
            }
    }
    
    public Component getComponentByName(String name) {
            if (componentMap.containsKey(name)) {
                    return (Component) componentMap.get(name);
            }
            else return null;
    }
    
  4. Vous avez maintenant un HashMap qui mappe tous les composants existants dans votre volet frame/content/panel/etc avec leurs noms respectifs.

  5. Pour accéder maintenant à ces composants, il suffit d'appeler getComponentByName (nom de chaîne). Si un composant portant ce nom existe, il le retournera. Sinon, il retourne null. Il vous incombe de définir le type de composant. Je suggère d'utiliser instanceof pour être sûr.

Si vous envisagez d'ajouter, de supprimer ou de renommer des composants à un moment quelconque de l'exécution, il serait judicieux d'ajouter des méthodes permettant de modifier HashMap en fonction de vos modifications.

27
Jesse Strickland

Chaque Component peut avoir un nom, accessible via getName() et setName(), mais vous devrez écrire votre propre fonction de recherche.

6
trashgod

getComponentByName (cadre, nom)

SI vous utilisez NetBeans ou un autre IDE qui crée par défaut des variables privées (champs) pour contenir tous vos composants AWT/Swing, le code suivant peut fonctionner pour vous. Utilisez comme suit:

// get a button (or other component) by name
JButton button = Awt1.getComponentByName(someOtherFrame, "jButton1");

// do something useful with it (like toggle it's enabled state)
button.setEnabled(!button.isEnabled());

Voici le code pour rendre ce qui précède possible ...

import Java.awt.Component;
import Java.awt.Window;
import Java.lang.reflect.Field;

/**
 * additional utilities for working with AWT/Swing.
 * this is a single method for demo purposes.
 * recommended to be combined into a single class
 * module with other similar methods,
 * e.g. MySwingUtilities
 * 
 * @author http://javajon.blogspot.com/2013/07/Java-awtswing-getcomponentbynamewindow.html
 */
public class Awt1 {

    /**
     * attempts to retrieve a component from a JFrame or JDialog using the name
     * of the private variable that NetBeans (or other IDE) created to refer to
     * it in code.
     * @param <T> Generics allow easier casting from the calling side.
     * @param window JFrame or JDialog containing component
     * @param name name of the private field variable, case sensitive
     * @return null if no match, otherwise a component.
     */
    @SuppressWarnings("unchecked")
    static public <T extends Component> T getComponentByName(Window window, String name) {

        // loop through all of the class fields on that form
        for (Field field : window.getClass().getDeclaredFields()) {

            try {
                // let us look at private fields, please
                field.setAccessible(true);

                // compare the variable name to the name passed in
                if (name.equals(field.getName())) {

                    // get a potential match (assuming correct &lt;T&gt;ype)
                    final Object potentialMatch = field.get(window);

                    // cast and return the component
                    return (T) potentialMatch;
                }

            } catch (SecurityException | IllegalArgumentException 
                    | IllegalAccessException ex) {

                // ignore exceptions
            }

        }

        // no match found
        return null;
    }

}

Il utilise la réflexion pour parcourir les champs de la classe et voir s'il peut trouver un composant désigné par une variable du même nom. 

REMARQUE: le code ci-dessus utilise des génériques pour convertir les résultats dans le type que vous attendez. Vous devrez donc parfois être explicite sur le transtypage. Par exemple, si myOverloadedMethod accepte à la fois JButton et JTextField, vous devrez peut-être définir explicitement la surcharge que vous souhaitez appeler ...

myOverloadedMethod((JButton) Awt1.getComponentByName(someOtherFrame, "jButton1"));

Et si vous n'êtes pas sûr, vous pouvez obtenir une Component et la vérifier avec instanceof...

// get a component and make sure it's a JButton before using it
Component component = Awt1.getComponentByName(someOtherFrame, "jButton1");
if (component instanceof JButton) {
    JButton button = (JButton) component;
    // do more stuff here with button
}

J'espère que cela t'aides!

4
Jonathan

vous pouvez conserver une référence à la première image JFrame dans la deuxième image JFrame et simplement parcourir JFrame.getComponents () en vérifiant le nom de chaque élément.

2
Andy

J'avais besoin d'accéder à des éléments dans plusieurs JPanels qui étaient dans une seule JFrame.

@ Jesse Strickland a posté une excellente réponse, mais le code fourni ne peut accéder à aucun élément imbriqué (comme dans mon cas, dans JPanel).

Après googling supplémentaire, j'ai trouvé cette méthode récursive fournie par @aioobe ici .

En combinant et en modifiant légèrement le code de @ Jesse Strickland et de @aioobe, j'ai obtenu un code fonctionnel qui peut accéder à tous les éléments imbriqués, quelle que soit leur profondeur:

private void createComponentMap() {
    componentMap = new HashMap<String,Component>();
    List<Component> components = getAllComponents(this);
    for (Component comp : components) {
        componentMap.put(comp.getName(), comp);
    }
}

private List<Component> getAllComponents(final Container c) {
    Component[] comps = c.getComponents();
    List<Component> compList = new ArrayList<Component>();
    for (Component comp : comps) {
        compList.add(comp);
        if (comp instanceof Container)
            compList.addAll(getAllComponents((Container) comp));
    }
    return compList;
}

public Component getComponentByName(String name) {
    if (componentMap.containsKey(name)) {
        return (Component) componentMap.get(name);
    }
    else return null;
}

L'utilisation du code est exactement la même que dans le code @Jesse Strickland.

1
kazy

Vous pouvez déclarer une variable comme une variable publique, puis obtenir le texte ou l'opération de votre choix, puis y accéder dans l'autre cadre (s'il est dans le même package), car il est public.

1
Mojo_Jojo

Si vos composants sont déclarés dans la même classe à partir de laquelle vous les manipulez, vous accédez simplement à ces composants en tant qu'attributs de le nom de la classe .

public class TheDigitalClock {

    private static ClockLabel timeLable = new ClockLabel("timeH");
    private static ClockLabel timeLable2 = new ClockLabel("timeM");
    private static ClockLabel timeLable3 = new ClockLabel("timeAP");


    ...
    ...
    ...


            public void actionPerformed(ActionEvent e)
            {
                ...
                ...
                ...
                    //set all components transparent
                     TheDigitalClock.timeLable.setBorder(null);
                     TheDigitalClock.timeLable.setOpaque(false);
                     TheDigitalClock.timeLable.repaint();

                     ...
                     ...
                     ...

                }
    ...
    ...
    ...
}

Et, vous pouvez pouvoir accéder aux composants de classe en tant qu'attributs du nom de classe à partir d'autres classes du même espace de nom . Je peux accéder aux attributs protégés (variables de membre de classe), peut-être aussi aux composants publics. Essayez le!

0