2011-02-10 19 views
14

ho in un JFrame alcuni componenti che voglio per riferirsi in un altro JFrame e voglio per farli per nome e non faccio metodi get/set pubblici per ciascuno.Ottenere un componente Swing per nome

C'è un modo da Swing per ottenere un riferimento al componente con il suo nome come fa C#?

ad es. form.Controls["text"]

Grazie

+1

Window.getWindows() e quindi scansiona quello che ti serve – bestsss

+1

Perché nel mondo ti piacerebbe farlo?In questo modo, si perdono due importanti controlli del compilatore statico: - Innanzitutto, il campo esiste. - In secondo luogo, è del tipo corretto. Inoltre, la ricerca dinamica è più lenta dell'avere un riferimento al campo. – fortran

+0

Ad esempio, a causa delle API temute, in cui non si ha accesso diretto ad alcuni componenti che si desidera modificare. –

risposta

27

So che questa è una vecchia domanda, ma mi sono trovato a chiedermelo proprio ora. Volevo un modo semplice per ottenere componenti per nome, quindi non dovevo scrivere ogni volta un codice complicato per accedere a componenti diversi. Ad esempio, con un JButton accedere al testo in un campo di testo o una selezione in un elenco.

La soluzione più semplice è rendere tutte le variabili del componente variabili di classe in modo che sia possibile accedervi ovunque. Tuttavia, non tutti vogliono farlo, e alcuni (come me) stanno usando editor GUI che non generano i componenti come variabili di classe.

La mia soluzione è semplice, mi piacerebbe pensare, e in realtà non viola nessuno standard di programmazione, per quanto ne so (riferendosi a ciò che stava arrivando fortran). Consente un modo semplice e diretto per accedere ai componenti per nome.

  1. Creare una variabile di classe Mappa. È necessario importare HashMap al numero . Ho chiamato il mio componentMap per semplicità.

    private HashMap componentMap; 
    
  2. Aggiungi tutti i componenti al telaio come normale.

    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. Definire i seguenti due metodi nella classe. Avrete bisogno di importare componente se non l'hai già:

    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. Ora hai un HashMap che mappa tutti i componenti attualmente esistenti nel telaio/pannello di contenuto/pannello/etc per i loro rispettivi nomi .

  5. Per accedere a questi componenti, è semplice come una chiamata a getComponentByName (nome stringa). Se esiste un componente con quel nome, restituirà quel componente. In caso contrario, restituisce null. È responsabilità dell'utente trasmettere il componente al tipo corretto. Suggerisco di usare instanceof per essere sicuro.

Se avete intenzione di aggiungere, rimuovere o rinominare i componenti in qualsiasi momento durante il runtime, vorrei prendere in considerazione l'aggiunta di metodi che modificano la HashMap in base alle proprie modifiche.

+0

Sì, penso che sia una buona soluzione. Grazie per il codice :) – xdevel2000

+1

Ho avuto problemi con JPanels concatenati sul mio modulo. Quindi, una versione leggermente modivied cammina anche attraverso contenente Container: \t privato Componente getComponentByName (String name) { \t \t ritorno getComponentByName (. GetMainFrame() getRootPane(), nome); \t} \t \t privato Componente getComponentByName (root Container, String name) { \t \t per (componente C: root.getComponents()) { \t \t \t se (name.equals (c.getName())) { \t \t \t \t ritorno c; \t \t \t} \t \t \t if (c instanceof Container) { \t \t \t \t risultato Component = getComponentByName ((Container) c, nome); \t \t \t \t if (risultato! = Null) { \t \t \t \t \t risultato di ritorno; \t \t \t \t} \t \t \t} \t \t} \t \t ritorno nullo; \t} –

+0

Semplice ed ellisante – kazy

1

è possibile dichiarare una variabile come una pubblica quindi ottenere il testo o qualsiasi operazione che si desidera e quindi è possibile accedervi in ​​un altro telaio (se nella stessa confezione) perché è pubblico.

2

è possibile mantenere un riferimento al primo JFrame nel secondo JFrame e scorrere semplicemente attraverso JFrame.getComponents(), controllando il nome di ciascun elemento.

6

Ogni Component può avere un nome, accessibile tramite getName() e setName(), ma è necessario scrivere la propria funzione di ricerca.

4

getComponentByName (telaio, nome)

se si sta utilizzando NetBeans IDE o un altro che di default crea variabili private (campi) per contenere tutti i componenti AWT/Swing, quindi il seguente codice può funzionare per te. Utilizzare come segue:

// 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()); 

Ecco il codice per fare quanto sopra è possibile ...

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

} 

Si utilizza la riflessione per guardare attraverso i campi della classe per vedere se si riesce a trovare un componente che si riferisce a da una variabile con lo stesso nome

NOTA: il codice sopra riportato utilizza i generici per trasmettere i risultati a qualsiasi tipo che ci si aspetta, quindi in alcuni casi potrebbe essere necessario esplicitare il tipo di trasmissione. Per esempio, se myOverloadedMethod accetta sia JButton e JTextField, potrebbe essere necessario definire esplicitamente il sovraccarico che si desidera chiamare ...

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

E se non siete sicuri, è possibile ottenere un Component e controllare con 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 
} 

Spero che questo aiuti!

1

Avevo bisogno di accedere agli elementi all'interno di più JPanel s che erano all'interno di un singolo JFrame.

@Jesse Strickland ha pubblicato un'ottima risposta, ma il codice fornito non è in grado di accedere a elementi nidificati (come nel mio caso, all'interno di JPanel).

Dopo ulteriore ricerca su google ho trovato questo metodo ricorsivo fornito da @aioobe here.

combinando e modificando leggermente il codice di @Jesse Strickland e @aioobe Ho un codice di lavoro che possono accedere a tutti gli elementi nidificati, non importa quanto in profondità sono:

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

utilizzo del codice è esattamente come nel codice @Jesse Strickland.

0

Se i componenti vengono dichiarati all'interno della stessa classe da cui li stai manipolando, è sufficiente accedere a questi componenti come attributi di il nome della 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(); 

        ... 
        ... 
        ... 

       } 
    ... 
    ... 
    ... 
} 

E, si potrebbe essere in grado di accedere ai componenti di classe come attributi del nome della classe di altre classi dello stesso spazio dei nomi troppo. Posso accedere agli attributi protetti (variabili membro della classe), forse puoi anche accedere ai componenti pubblici. Provalo!

Problemi correlati