In our project my teammate notice unusual behavior for radio button, when inside action listener there is SwingUtilites.invokeLater call. Archetecture of the action listener doesn't allow to avoid this call because is designed to start another thread, and then there is a switch back to AWT thread.
Is there a way to fix this? I mean change the state of displayed component.
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.ButtonGroup;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JRadioButton;
import javax.swing.SwingUtilities;
import javax.swing.UIManager;
import javax.swing.UnsupportedLookAndFeelException;
import javax.swing.WindowConstants;
public class RadioButtonTest {
public static void main(String[] args) {
try {
UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
} catch (ClassNotFoundException | InstantiationException | IllegalAccessException
| UnsupportedLookAndFeelException e1) {
e1.printStackTrace();
}
JFrame frame = new JFrame();
JPanel panel = new JPanel();
frame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
frame.setSize(200, 200);
frame.add(panel);
ButtonGroup group = new ButtonGroup();
JRadioButton b1 = new JRadioButton("Button 1");
final JRadioButton b2 = new JRadioButton("Button 2");
b2.addActionListener(new ActionListener() {
@Override
public void actionPerformed(ActionEvent arg0) {
Runnable action = new Runnable() {
@Override
public void run() {
try {
Thread.sleep(2500);
} catch (InterruptedException e) {
Thread.currentThread().interrupt();
e.printStackTrace();
}
}
};
SwingUtilities.invokeLater(action);
}
});
group.add(b1);
group.add(b2);
panel.add(b1);
panel.add(b2);
frame.setVisible(true);
}
}
Use SwingWorker, try this code:
SwingWorker is executed on separate worker thread which is invoked by event dispatcher thread by calling execute method. SwingUtilities.invokeLater method just imposes run method to be executed asynchronously on the event dispatching thread, so calling Thread.sleep inside it will freezes the event dispatch thread which affects the GUI.
It looks like you want to avoid repeatedly initiating a long running background task. Instead of a
JRadioButton
, use the parentJToggleButton
, and set it's name and action to Cancel when the background task is started. AFuture
such asSwingWorker
makes this convenient. A related example usingJButton
is seen here.