Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

ClassCastException with JDialog and Thread

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

like image 424
DanielFH Avatar asked Jul 21 '26 00:07

DanielFH


1 Answers

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.

like image 124
Peter Walser Avatar answered Jul 23 '26 15:07

Peter Walser