2010-09-23 6 views
2

J'ai une liste de Map.Entry<String,Integer> que je suis en boucle, et pour chacun d'eux, en créant un JLabel/JSpinner représentant cette entrée particulière.Java/Swing: mettre à jour les données sur stateChange

Comment puis-je faire en sorte que lorsque le ChangeListener se déclenche sur le JSpinner, il met à jour cette entrée pour refléter la nouvelle valeur?

Mon code ressemble

for (Map.Entry<String,Integer> entry : graph.getData()) { 
    SpinnerNumberModel model = new SpinnerNumberModel(
     entry.getValue(),(Integer)0,(Integer)100,(Integer)5); 
    JSpinner spinner = new JSpinner(model); 

    JLabel label = new JLabel(entry.getKey()); 

    spinner.addChangeListener(new ChangeListener() { 
     public void stateChanged(ChangeEvent e) { 
      entry.setValue((Integer)((JSpinner)e.getSource()).getValue()); 
     } 
    }); 

    // more stuff 
} 

Toutefois, cela ne fonctionne pas, parce que l'entrée soit doit être définitive ou de niveau objet, et il est non plus.

Existe-t-il un moyen plus simple, comme le dataSource de C# qui lie directement l'objet au cône? Ou comment puis-je faire ce travail?

+1

Impossible de rendre l'entrée définitive? comme pour (final Map.Entry entrée: graph.getData()) ....? –

Répondre

2

Il existe plusieurs options si vous souhaitez conserver les codes JLabel et JSpinner. Utilisez la réponse de @ trashgod si la carte peut devenir grande.

  1. commentaire de MAUVAIS par @Suresh Kumar: final Map.Entry<String,Integer> entry
  2. MAL Ajouter spinner.putClientProperty("MyEntryKey", entry), puis dans votre ChangeListener obtenir l'entrée avec spinner.getClientProperty.
  3. Ajoutez spinner.putClientProperty("MyEntryKey", entry.getKey()), puis dans votre ChangeListener graph.put(spinner.getClientProperty(), ...).
  4. De la réponse @ Michael (pas sûr si c'est éthique): Ajouter final String key = entry.getKey(), puis dans votre ChangeListener graph.put(key, ...).
  5. Laissez votre classe englobante mettre en œuvre ChangeListener pour éviter un ChangeListener par JSpinner:

    public void stateChanged (ChangeEvent e) { JSpinner spinner = (JSpinner) e.getSource(); graph.put ((String) spinner.getClientProperty ("MyEntryKey"), (Entier) spinner.getValue()); }

BTW graph.getData() semble un peu bizarre. Si implémente Map, vous devez utiliser graph.entrySet().

+0

'Carte.Les références d'entrée ne sont pas valides après la fin de l'itérateur, de sorte que seule la solution n ° 3 (originale) fonctionnera de manière fiable. –

+0

Oups, désolé pour une telle erreur n00b. Je suppose que je devrais vraiment obtenir les votes «-2 + 1 = -1». –

+0

Eh bien, aucun graphique n'est un 'Map', mais il en contient un. Ce n'est pas non plus un graphique comme avec les arêtes et les sommets. C'est une façon TRÈS simple de représenter les données à afficher dans un graphique à secteurs/barres/lignes/etc. –

1

En particulier si le nombre d'entrées Map est grande, pensez à utiliser un JTable, avec votre Map comme le noyau du modèle de données et une coutume rendent/éditeur extension JSpinner. Il y a un exemple connexe here.

1

@Suresh a raison d'utiliser final dans la boucle for, mais puisque les valeurs de Map.Entry ne sont pas viables en dehors de l'itérateur, cela causerait des problèmes. Une autre possibilité pour celui-ci à sens unique de liaison serait

for (Map.Entry<String, Integer> entry : graph.getData()) { 
    ... 
    final String key = entry.getKey(); 

    spinner.addChangeListener(new ChangeListener() { 
     public void stateChanged(ChangeEvent e) { 
      graph.put(key, (Integer)((JSpinner)e.getSource()).getValue()); 
     } 
    }); 

Pour une données plus complètes de liaison, vous voudrez peut-être un objet plus complexe à se lier contre. Voir les ValueModel de l'API de liaison jgoodies et SpinnerAdapterFactory, par exemple.

Questions connexes