JDialog 和 Thread 的 ClassCastException

发布于 2024-09-03 21:13:10 字数 5266 浏览 8 评论 0原文

我有一个 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;

    }
}

}

这是异常转换:

线程“AWT-EventQueue-0”中出现异常 java.lang.ClassCastException 位于 javax.swing.LayoutComparator.compare(LayoutComparator.java:61) 在 java.util.Arrays.mergeSort(Arrays.java:1293) 在 java.util.Arrays.mergeSort(Arrays.java:1282) 在 java.util.Arrays.sort(Arrays.java:1210) 在 java.util.Collections.sort(Collections.java:159) 在 javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(SortingFocusTraversalPolicy.java:119) 在 javax.swing.SortingFocusTraversalPolicy.getFirstComponent(SortingFocusTraversalPolicy.java:434) 在 javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(LayoutFocusTraversalPolicy.java:148) 在 javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(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)

谢谢。 丹尼尔

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

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

不弃不离 2024-09-10 21:13:10

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

想象一下 UI 即将重新绘制自身(以及布局内容),而您只需使用另一个线程同时更改 UI 的某些部分即可进行干扰。在这种情况下,很可能会发生混乱。

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

处理这个问题的正确方法是让后台线程执行任何与 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 并等待它被执行。

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.

口干舌燥 2024-09-10 21:13:10

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

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

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

或者也许应该使用 SwingWorker 而不是 Thread。有关详细信息,请阅读 Swing 教程中有关并发的部分。

或者更好的方法是启动 Swing Timer 来安排对话框的关闭。当定时器触发时,代码会在 EDT 上自动执行。 Swing 教程还有一个关于使用计时器的部分。

All updates to Swing components should be done on the Event Dispatch Thread (EDT).

In your Thread you attempt to pack() the dialog every second. This code is NOT executing on the EDT.

Try using a SwingUtilities.invokeLater(...) to do the pack().

Or maybe a SwingWorker should be used instead of the Thread. Read the section from the Swing tutorial on Concurrency for more information.

Or maybe even a better approach is to start a Swing Timer to schedule closing of the dialog. When the Timer fires the code is automatically executed on the EDT. The Swing tutorial also has a section on using Timers.

策马西风 2024-09-10 21:13:10

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

尝试:

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

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

You are launching the dialog from a thread other than the Event Dispatcher thread. Any UI create/update should be from within the Swing's event dispatcher thread.

Try:

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

NOTE: Any update to an UI before it's shown (visible) may be done from outside the event dispatcher thread. BUT once the UI is displayed any changes should always be done from within the Event Dispatch thread.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文