从JPanel的子类调用RemoveAll()时出现奇怪的Swing错误

Sha*_*503 1 java swing

我正在研究一个Sudoku谜题生成器,并在调用JPanel的RemoveAll()方法之后/期间遇到一些间歇性的swing异常.当我在eclipse的调试模式下运行时,不会出现异常.以下是相关类的代码:

import java.awt.FlowLayout;
import java.awt.GridLayout;

import javax.swing.JLabel;
import javax.swing.JPanel;

/**
 * Represents a cell in the GUI Grid display
 * @author alex
 *
 */
public class CellGUI extends JPanel {



    public CellGUI()
    {
        super();

        this.setLayout(new GridLayout(3,3));

        for(int i = 1;i <=9;i++)
        {
            add(new JLabel("" + i));
        }

        setVisible(true);
    }

    public void clear()
    {
        this.removeAll();
        this.validate();
        this.setLayout(new GridLayout(3,3));

        for(int i = 1;i <= 9; i++)
        {
            add(new JLabel("" + i));
        }       

    }

    public void setValue(int newVal)
    {
        if (newVal == 0)
        {
            clear();
        }
        else
        {

            this.removeAll(); // this line appears to be the problem 

            //this.updateUI();
            //this.setLayout(new FlowLayout());

            //add(new   JLabel("" + newVal));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

它通常会吐出这个异常:

Exception in thread "AWT-EventQueue-0" java.lang.ClassCastException
    at javax.swing.LayoutComparator.compare(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.mergeSort(Unknown Source)
    at java.util.Arrays.sort(Unknown Source)
    at java.util.Collections.sort(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.enumerateAndSortCycle(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.getFirstComponent(Unknown Source)
    at javax.swing.LayoutFocusTraversalPolicy.getFirstComponent(Unknown Source)
    at javax.swing.SortingFocusTraversalPolicy.getDefaultComponent(Unknown Source)
    at java.awt.FocusTraversalPolicy.getInitialComponent(Unknown Source)
    at java.awt.DefaultKeyboardFocusManager.dispatchEvent(Unknown Source)
    at java.awt.Component.dispatchEventImpl(Unknown Source)
    at java.awt.Container.dispatchEventImpl(Unknown Source)
    at java.awt.Window.dispatchEventImpl(Unknown Source)
    at java.awt.Component.dispatchEvent(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.SequencedEvent.dispatch(Unknown Source)
    at java.awt.EventQueue.dispatchEventImpl(Unknown Source)
    at java.awt.EventQueue.access$000(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.awt.EventQueue$1.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.awt.EventQueue$2.run(Unknown Source)
    at java.security.AccessController.doPrivileged(Native Method)
    at java.security.AccessControlContext$1.doIntersectionPrivilege(Unknown Source)
    at java.awt.EventQueue.dispatchEvent(Unknown Source)
    at java.awt.EventDispatchThread.pumpOneEventForFilters(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForFilter(Unknown Source)
    at java.awt.EventDispatchThread.pumpEventsForHierarchy(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.pumpEvents(Unknown Source)
    at java.awt.EventDispatchThread.run(Unknown Source)
Run Code Online (Sandbox Code Playgroud)

我想我的天真,我可能会以错误的方式做这件事.有任何想法吗?

编辑:根据请求,我发布了其他代码.

该类调用CellGUI的setValue方法:

public class GridGUI extends JPanel {

    ArrayList<CellGUI> cells = new ArrayList<CellGUI>();

    public GridGUI()
    {

        this.setLayout(new GridLayout(9,9));


        for(int i = 0; i < 81;i++)
        {
            CellGUI cell = new CellGUI();
            cells.add(cell);
            add(cell);
        }

    }


    public void updateGrid(Grid g)
    {
        for(int i = 0;i<81;i++)
        {
            cells.get(i).setValue(g.getValue(i));
        }
    }
}
Run Code Online (Sandbox Code Playgroud)

GridGUI类由扩展JFrame的类创建和管理:

public class GUI extends JFrame {   
...
public GUI() 
    {
        this.setLayout(new BorderLayout());
        add(gridGUI,BorderLayout.CENTER);

        JPanel panel = new JPanel();
        panel.setLayout(new FlowLayout());
        panel.add(isValidLabel);
        panel.add(isSolvableLabel);
        panel.setVisible(true);

        add(panel, BorderLayout.SOUTH);

        this.setSize(600, 600);

        setVisible(true);       

    }
    public void loadGrid(String path)
    {
        grid = new Grid(path);
        grid.print();

        gridGUI.updateGrid(grid);

        updateLabels();
    }
...
}
Run Code Online (Sandbox Code Playgroud)

这是我的主要课程:

public static void main(String[] args) 
{       
    GUI gui = new GUI();
    gui.loadGrid(args[0]);
}
Run Code Online (Sandbox Code Playgroud)

And*_*son 6

Swing应用程序中的"间歇/偶然错误".通常是通过更新EDT的UI来引起的.有关更多详细信息,请参阅Swing中的并发.

请注意,为了更好地提供帮助,请发布SSCCE.如果我上面的怀疑是问题的原因,那么问题实际上是代码未显示.


Paŭ*_*ann 5

因此,查看堆栈跟踪显示当FocusManager尝试获取第一个组件时发生错误.为此,您的FocusTraversalPolicy尝试按"布局顺序"对组件进行排序,这意味着大致在列和行中.对于GridLayout,这应该是完全无关紧要的.我们来看看代码吧LayoutComparator.它在某些地方抛出ClassCastException:

        if (a == null) {
            // 'a' is not part of a Window hierarchy. Can't cope.
            throw new ClassCastException();
        }
Run Code Online (Sandbox Code Playgroud)

a是这里包含Window,或者null如果不存在这样的Window.

因此,看起来您的组件尚未在组件树中完全注册.正如其他人所说,如果你在不在AWT事件派发线程中的GUI中做了一些更改,就会发生这种情况.

要避免这种情况,请在调用中将所有更改包装到GUI(包括创建组件,如上面的构造函数调用).(有时候更有用,你也可以在SwingUtilities中使用相同名称的方法.)在你的情况下,改变很简单:EventQueue.invokeLater(...)invokeAndWait

public static void main(String[] args) 
{
    EventQueue.invokeLater(new Runnable() { public void run() {
        GUI gui = new GUI();
        gui.loadGrid(args[0]);
    }});
}
Run Code Online (Sandbox Code Playgroud)