I have a list of Map.Entry<String,Integer>
s that I am looping through, and for each one, making a JLabel
/JSpinner
representing that particular entry.
How can I make it so that when the ChangeListener
fires on the JSpinner
, it updates that entry to reflect the new value?
My code looks like
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
}
However, this does not work, because entry either needs to be final or object-level, and it is neither.
Is there an easier way, like C#'s dataSource
that directly binds the object to the spinner? Or how can I make this work?
There are several options if you want to stick with individual JLabel
and JSpinner
. Use @trashgod's answer if the map could get large.
- WRONG Per @Suresh Kumar's comment:
final Map.Entry<String,Integer> entry
- WRONG Add
spinner.putClientProperty("MyEntryKey", entry)
, then in your ChangeListener get the entry withspinner.getClientProperty
. - Add
spinner.putClientProperty("MyEntryKey", entry.getKey())
, then in your ChangeListenergraph.put(spinner.getClientProperty(), ...)
. - From @Michael's answer (not sure if this is ethical): Add
final String key = entry.getKey()
, then in your ChangeListenergraph.put(key, ...)
. Let your enclosing class implement
ChangeListener
to avoid oneChangeListener
perJSpinner
:public void stateChanged(ChangeEvent e) { JSpinner spinner = (JSpinner)e.getSource(); graph.put((String)spinner.getClientProperty("MyEntryKey"), (Integer)spinner.getValue()); }
BTW graph.getData()
looks a bit odd. If graph
implements Map
, you should use graph.entrySet()
.
Particularly if the number of Map
entries is large, consider using a JTable
, with your Map
as the core of the data model and a custom render/editor extending JSpinner
. There's a related example here.
@Suresh is right about using final
in the for loop, but since Map.Entry
values aren't viable outside of the iterator, this would lead to trouble. Another possibility for this one-way binding would be
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());
}
});
For a more complete data binding, you may want a more complex object to bind against. See the jgoodies binding API's ValueModel
and SpinnerAdapterFactory
, for example.
精彩评论