I'm using a numeric JSpinner to select stuff to display by other components
in my GUI. The user may make modifications to the other components which
the program validates. One scenario that triggers validation is for the
user to select a different number with the spinner. If validation fails, I
want to show an error message, set the spinner to some other value, and
allow the user to correct the error. The implementation is to put a
ChangeEvent listener on the JSpinner and from the event handler do the
validation. If the validation fails, I display an error message with
JOptionPane and reset the spinner to some other value. Resetting triggers a
new ChangeEvent so I use a boolean flag to ignore the event in this case. I
don't like the flag but the event is triggered whether the JSpinner is
modified via a mouse click or through code. This is different, for example,
than a JCheckBox and an ActionEvent which is not triggered by setSelected().
I found that the code goes into recursive ChangeEvents. However, if I
remove the message display there is no recursion. In other words, invoking
JOptionPane.showMessageDialog() as a child of a JFrame that contains a
JSpinner object is causing an event against the JSpinner object. Is this
logical? A simple demonstration of this problem is attached. Running the
program with no parameter suppresses the error message whereas running with
any parameter enables the error message. The behavior should be as I
described. How can I eliminate this recursion?
Environment is JRE 1.4.2 and development tool is Eclipse 3.1.0.
import javax.swing.JOptionPane;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JSpinner;
public class jspinner_bug extends JFrame {
private static final long serialVersionUID = 1L;
private JPanel jContentPane = null;
private JSpinner jSpinner = null;
private boolean ignore = false;
private static boolean showMsg = false;
// instantiate the spinner and implement the event handler
private JSpinner getJSpinner() {
if (jSpinner == null) {
jSpinner = new JSpinner();
jSpinner.setLocation(50, 20);
jSpinner.setSize(50, 20);
jSpinner.addChangeListener(new javax.swing.event.ChangeListener() {
public void stateChanged(javax.swing.event.ChangeEvent e) {
if(ignore)
ignore = false;
else
makeMess();
}
});
}
return jSpinner;
}
// Eclipse generate main()
public static void main(String[] args) {
if(args.length > 0)
showMsg = true;
jspinner_bug application = new jspinner_bug();
application.show();
}
// Eclipse generated constructor
public jspinner_bug() {
super();
initialize();
}
// Eclipse generated application initialization
private void initialize() {
this.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
this.setSize(150, 100);
this.setContentPane(getJContentPane());
}
// Eclipse generated content pane initialization
private JPanel getJContentPane() {
if (jContentPane == null) {
jContentPane = new JPanel();
jContentPane.setLayout(null);
jContentPane.add(getJSpinner(), null);
}
return jContentPane;
}
// show message if started with run-time parameter, set spinner
private void makeMess() {
if(showMsg)
JOptionPane.showMessageDialog(this,
"Message",
"Bug",
JOptionPane.ERROR_MESSAGE);
Integer val = (Integer)jSpinner.getValue();
int intVal = val.intValue();
ignore = true;
jSpinner.setValue(new Integer(intVal+5));
}
}
Raymond Cruz - 28 Jun 2005 00:09 GMT
TIA for anyone who was going to take a crack at answering this. A colleague
who apparently is a better googler than me found that this is documented
Java bug #4840869 and there is a patch the user can add for 1.4. Also it is
said to be fixed in 1.5. In short, the API leaves the focus on the up or
down button of the spinner when it brings up the JOptionPane and this causes
extra increments of the spinner, which in my case resulted in extra events.
RC
> I'm using a numeric JSpinner to select stuff to display by other
> components in my GUI. ...