I have a JDialog with a thread in it. It sporadically gives me a ClassCastException when the dialog is created (which means I can have succesful ones with no exception), and I have no clue to where it should occur.
Here's a snippet of my JDialog class
public class ConfirmExitDialog extends JDialog implements Runnable,
ActionListener {
private static final long serialVersionUID = -8762051370686039110L;
private Thread dialogThread;
private boolean running;
private int result, count = 60;
private HandleExit handleExit = null;
// GUI
private JOptionPane optionPane;
private JLabel msgLabel = new JLabel();
private JButton btnYes;
private JButton btnNo;
private void updateLabelText() {
msgLabel.setText("<html>Ønsker du at afslutte dagens salg?<br>Programmet afslutter automatisk om " + count + " sekunder.</html>");
}
public int getResult() {
return result;
}
public ConfirmExitDialog(Frame frame, HandleExit handleExit) {
super(frame, false);
this.handleExit = handleExit;
setTitle("Afslut dagens salg?");
display();
running = true;
if (dialogThread == null) {
dialogThread = new Thread(this, "ConfirmExitDialog");
dialogThread.start();
}
this.setModal(true);
}
public void close() {
if (dialogThread != null)
running = false;
}
private void display() {
setLayout(new BorderLayout());
// Buttons
btnYes = new JButton("Ja");
btnYes.addActionListener(this);
btnYes.setMnemonic('J');
add(btnYes, BorderLayout.WEST);
btnNo = new JButton("Nej");
btnNo.addActionListener(this);
btnNo.setMnemonic('N');
add(btnNo, BorderLayout.EAST);
JButton[] buttons = { btnYes, btnNo };
updateLabelText();
optionPane = new JOptionPane(msgLabel, JOptionPane.QUESTION_MESSAGE,
JOptionPane.YES_NO_OPTION, null, buttons, buttons[0]);
setContentPane(optionPane);
setDefaultCloseOperation(DISPOSE_ON_CLOSE);
// Handle window closing correctly.
setDefaultCloseOperation(DO_NOTHING_ON_CLOSE);
addWindowListener(new WindowAdapter() {
public void windowClosing(WindowEvent we) {
/*
* Instead of directly closing the window, we're going to change the
* JOptionPane's value property.
*/
optionPane.setValue(new Integer(JOptionPane.CLOSED_OPTION));
}
});
pack();
setVisible(true);
}
private void countDown() {
updateLabelText();
count--;
}
@Override
public void run() {
// TODO Auto-generated method stub
try {
display();
while (running && count > 0) {
System.out.println("Countdown " + count);
pack();
countDown();
Thread.sleep(1000);
}
setVisible(false);
if (count == 0)
handleExit.closeApplication(true, true);
} catch (InterruptedException ie) {
// Thread stopped
}
}
@Override
public void actionPerformed(ActionEvent event) {
Object src = event.getSource();
if (src == btnYes) {
setVisible(false);
result = JOptionPane.YES_OPTION;
running = false;
handleExit.closeApplication(true, false);
}
if (src == btnNo) {
setVisible(false);
result = JOptionPane.NO_OPTION;
running = false;
}
}
}
Here's the exception cast:
Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException at javax.swing.LayoutComparator.compare(LayoutComparator.java:61) at java.util.Arrays.mergeSort(Arrays.java:1293) at java.util.Arrays.mergeSort(Arrays.java:1282) at java.util.Arrays.sort(Arrays.java:1210) at java.util.Collections.sort(Collections.java:159) at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:119) at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:434) at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:148) at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(SortingFocusTraversalPolicy.java:511) at java.awt.FocusTraversalPolicy.getInitialComponent(FocusTraversalPolicy.java:152) at java.awt.Window.getMostRecentFocusOwner(Window.java:2131) at java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:629) at java.awt.Component.dispatchEventImpl(Component.java:4502) at java.awt.Container.dispatchEventImpl(Container.java:2099) at java.awt.Window.dispatchEventImpl(Window.java:2478) at java.awt.Component.dispatchEvent(Component.java:4460) at java.awt.EventQueue.dispatchEvent(EventQueue.java:599) at java.awt.SequencedEvent.dispatch(SequencedEvent.java:101) at java.awt.EventQueue.dispatchEvent(EventQueue.java:597) at java.awt.EventDispatchThread.pumpOneEventForFilters(EventDispatchThread.java:269) at java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) at java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) at java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) at java.awt.EventDispatchThread.run(EventDispatchThread.java:122)
Thank you. Daniel
Doing UI modifications in a Thread other than Swing's EventDispatchThread is strongly discouraged, as it can and will lead to weird side effects (just as the one you encountered).
Immagine the UI is about to repaint itself (and layout stuff) and you just interfer by changing parts of the UI at the same time using another thread. In such a situation chaos is verly likely to ensue.
For details see the Java Tutorials Lesson Concurrency in Swing
The correct way to deal with this is to have the background thread do any work that is not UI related, and schedule a UI update job in the EventDispatchThread (which will execute the job between handling events).
Example:
Thread t = new Thread() {
public void run () {
// do background work
SwingUtilities.invokeLater(new Runnable() {
public void run () {
// update UI parts
}
});
}
};
t.start();
SwingUtilities.invokeLater(Runnnable) will schedule a Runnable for later execution, whereas
SwingUtilities.invokeAndWait(Runnnable) will schedule a Runnable and wait until it has been executed.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With