3

我有一个带有线程的 JDialog。创建对话框时,它偶尔会给我一个 ClassCastException (这意味着我可以毫无例外地成功),而且我不知道它应该在哪里发生。

这是我的 JDialog 类的片段

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;

    }
}

}

这是异常演员表:

java.util.Arrays.mergeSort(Arrays.java:1293) 的 java.util.Arrays.mergeSort(Arrays.java:1293) 的 javax.swing.LayoutComparator.compare(LayoutComparator.java:61) 的线程“AWT-EventQueue-0”java.lang.ClassCastException 中的异常。 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) 在 javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:434) 在 javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:148) 在 javax.swing.SortingFocusTraversalPolicy.getDefaultPolicy(SortingFocusTraversalPolicy.java:511).在 java.awt.FocusTraversalPolicy。getInitialComponent(FocusTraversalPolicy.java:152) 在 java.awt.Window.getMostRecentFocusOwner(Window.java:2131) 在 java.awt.DefaultKeyboardFocusManager.dispatchEvent(DefaultKeyboardFocusManager.java:629) 在 java.awt.Component.dispatchEventImpl(Component.java :4502) 在 java.awt.Container.dispatchEventImpl(Container.java:2099) 在 java.awt.Window.dispatchEventImpl(Window.java:2478) 在 java.awt.Component.dispatchEvent(Component.java:4460) 在 java .awt.EventQueue.dispatchEvent(EventQueue.java:599) 在 java.awt.SequencedEvent.dispatch(SequencedEvent.java:101) 在 java.awt.EventQueue.dispatchEvent(EventQueue.java:597) 在 java.awt.EventDispatchThread。 pumpOneEventForFilters(EventDispatchThread.java:269) 在 java.awt.EventDispatchThread.pumpEventsForFilter(EventDispatchThread.java:184) 在 java.awt.EventDispatchThread.pumpEventsForHierarchy(EventDispatchThread.java:174) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:169) 在 java.awt.EventDispatchThread.pumpEvents(EventDispatchThread.java:161) 在 java. awt.EventDispatchThread.run(EventDispatchThread.java:122)

谢谢你。丹尼尔

4

3 回答 3

4

强烈建议不要在 Swing 的EventDispatchThread以外的线程中进行 UI 修改,因为它可能并且会导致奇怪的副作用(就像您遇到的那样)。

想象一下 UI 即将重新绘制自己(和布局的东西),而您只是通过使用另一个线程同时更改部分 UI 来进行干预。在这种情况下,很可能会出现混乱。

有关详细信息,请参阅 Swing 中的 Java 教程课程并发

处理这个问题的正确方法是让后台线程做任何与 UI 无关的工作,并在 EventDispatchThread 中安排一个 UI 更新作业(它将在处理事件之间执行作业)。

例子:

    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)将安排一个 Runnable 供以后执行,而 SwingUtilities.invokeAndWait(Runnnable)将安排一个 Runnable 并等到它执行完毕。

于 2010-06-03T14:37:33.243 回答
1

Swing 组件的所有更新都应在事件调度线程 (EDT) 上完成。

在您的线程中,您每秒都尝试打包()对话框。此代码不在 EDT 上执行。

尝试使用 SwingUtilities.invokeLater(...) 来执行 pack()。

或者也许应该使用 SwingWorker 而不是 Thread。阅读 Swing 教程中关于并发的部分以获取更多信息。

或者甚至更好的方法是启动一个 Swing Timer 来安排关闭对话框。当 Timer 触发时,代码会在 EDT 上自动执行。Swing 教程也有一节介绍如何使用定时器。

于 2010-06-03T14:25:21.297 回答
0

您从 Event Dispatcher 线程以外的线程启动对话框。任何 UI 创建/更新都应该来自 Swing 的事件调度程序线程。

尝试:

SwingUtilities.invokeLater(new Runnable() {
    public void run() {
        // show the UI here (display method in your logic?)
    }
});

注意:在显示(可见)之前对 UI 的任何更新都可以在事件调度程序线程之外完成。但是一旦显示 UI,任何更改都应始终在 Event Dispatch 线程中完成。

于 2010-06-03T16:16:54.570 回答