FULL PRODUCT VERSION :
java version "1.8.0"
Java(TM) SE Runtime Environment (build 1.8.0-b132)
Java HotSpot(TM) 64-Bit Server VM (build 25.0-b70, mixed mode)
ADDITIONAL OS VERSION INFORMATION :
Mac OS X 10.9.2
A DESCRIPTION OF THE PROBLEM :
http://docs.oracle.com/javase/8/docs/api/index.html
On this page, under java.awt.Checkbox.setState() function, it states:
... Programmatically setting the state of the checkbox will not trigger an ItemEvent. The only way to trigger an ItemEvent is by user interaction.
This works correctly on Linux. But on Mac OS X, the above statement is not followed. setState() call does trigger an ItemEvent to the listener.
STEPS TO FOLLOW TO REPRODUCE THE PROBLEM :
Compile the attached sample source code, and run "java test.Test" to start it. There are three checkbooks, left, tie, and right. If tie is on, change either left or right will change the state of the other, using setState(). Whenever an ItemEvent is triggered, it print the source on the console. On linux, this works according to the document. But on Mac, when tie checkbox is on, click either left or right will cause infinite loop of calling itemStateChanged. This is because setState() call erroneously send an ItemEvent to the listener.
EXPECTED VERSUS ACTUAL BEHAVIOR :
EXPECTED -
One user click on one checkbox, should generate only one ItemEvent. The setState() call should not generate further ItemEvent, just like the document says.
ACTUAL -
an infinite loop of itemStateChanged() calls.
REPRODUCIBILITY :
This bug can be reproduced always.
---------- BEGIN SOURCE ----------
package test;
import java.awt.*;
import java.awt.event.*;
class Test extends Frame implements WindowListener, ItemListener {
public static void main(String[] args) {
new Test();
}
Test() {
super("Test");
setLayout(new GridBagLayout());
GridBagConstraints grid = new GridBagConstraints();
grid.insets = new Insets(10, 10, 10, 10);
add(left = new Checkbox("Left"), grid);
add(tie = new Checkbox("Tie"), grid);
add(right = new Checkbox("Right"), grid);
addWindowListener(this);
left.addItemListener(this);
tie.addItemListener(this);
right.addItemListener(this);
pack();
setVisible(true);
}
public void windowClosing(WindowEvent event) {
System.exit(0);
}
public void windowOpened(WindowEvent event) {}
public void windowClosed(WindowEvent event) {}
public void windowIconified(WindowEvent event) {}
public void windowDeiconified(WindowEvent event) {}
public void windowActivated(WindowEvent event) {}
public void windowDeactivated(WindowEvent event) {}
public void itemStateChanged(ItemEvent event) {
Object source = event.getSource();
System.out.println("event from " + (source == left ? "left" :
source == tie ? "tie" : source == right ? "right" : "unknown"));
if (source == tie || !tie.getState()) return;
if (source == left) right.setState(!right.getState());
if (source == right) left.setState(!left.getState());
}
private Checkbox left, tie, right;
}
---------- END SOURCE ----------