Java 调用JPanel子类上的RemoveAll()时出现奇怪的Swing错误
我正在开发一个数独益智生成器,在调用JPanel的RemoveAll()方法之后/期间遇到了一些间歇性的swing异常。在eclipse的调试模式下运行时,不会出现异常。以下是相关课程的代码:Java 调用JPanel子类上的RemoveAll()时出现奇怪的Swing错误,java,swing,Java,Swing,我正在开发一个数独益智生成器,在调用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
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));
}
}
}
我觉得我的天真很可能是用了错误的方法。有什么想法吗
编辑:根据请求,我发布了附加代码
此类调用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));
}
}
}
我的主课叫它:
public static void main(String[] args)
{
GUI gui = new GUI();
gui.loadGrid(args[0]);
}
像这样的间歇性错误让我担心调用EDT的Swing代码,EDT是事件调度线程,它是主Swing线程,负责Swing图形和用户交互。您在哪里以及如何调用CellGUI#setValue(…)方法?它可能是关闭EDT的吗?像这样的间歇性错误让我担心调用EDT的Swing代码,EDT是事件调度线程,它是主Swing线程,负责Swing图形和用户交互。您在哪里以及如何调用CellGUI#setValue(…)方法?可能是EDT关闭了吗?Swing应用程序中的“间歇性/偶尔错误”。通常是由于在EDT之外更新UI造成的。有关更多详细信息,请参阅
请注意,为了更快地获得更好的帮助,请发布一个。如果我以上的怀疑是问题的原因,那么问题实际上是在未显示的代码中。Swing应用程序中的“间歇性/偶尔错误”。通常是由于在EDT之外更新UI造成的。有关更多详细信息,请参阅
请注意,为了更快地获得更好的帮助,请发布一个。如果我以上的怀疑是问题的原因,那么问题实际上是在代码中没有显示。因此,查看堆栈跟踪表明,错误发生在FocusManager尝试获取第一个组件时。为此,您的FocusTraversalPolicy尝试按“布局顺序”对组件进行排序,即大致按列和行排序。对于GridLayout,这应该是非常简单的。让我们看看
layoutparator
的代码。它在某些地方抛出ClassCastException:
if (a == null) {
// 'a' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
a是此处的包含窗口,如果不存在此类窗口,则为null
因此,看起来您的组件尚未在组件树中完全注册。正如其他人所说,如果您在不在AWT事件调度线程中时在GUI中进行一些更改,则可能会发生这种情况
为了避免这种情况,在调用EventQueue.invokeLater(…)
时,将对GUI的所有更改(包括创建组件,如上面的构造函数调用)包装起来。(有时,invokeAndWait
更有用,您也可以在SwingUtilities中使用相同的命名方法。)在您的例子中,更改非常简单:
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable() { public void run() {
GUI gui = new GUI();
gui.loadGrid(args[0]);
}});
}
因此,查看堆栈跟踪表明,当FocusManager尝试获取第一个组件时,会发生错误。为此,您的FocusTraversalPolicy尝试按“布局顺序”对组件进行排序,即大致按列和行排序。对于GridLayout,这应该是非常简单的。让我们看看
layoutparator
的代码。它在某些地方抛出ClassCastException:
if (a == null) {
// 'a' is not part of a Window hierarchy. Can't cope.
throw new ClassCastException();
}
a是此处的包含窗口,如果不存在此类窗口,则为null
因此,看起来您的组件尚未在组件树中完全注册。正如其他人所说,如果您在不在AWT事件调度线程中时在GUI中进行一些更改,则可能会发生这种情况
为了避免这种情况,在调用EventQueue.invokeLater(…)
时,将对GUI的所有更改(包括创建组件,如上面的构造函数调用)包装起来。(有时,invokeAndWait
更有用,您也可以在SwingUtilities中使用相同的命名方法。)在您的例子中,更改非常简单:
public static void main(String[] args)
{
EventQueue.invokeLater(new Runnable() { public void run() {
GUI gui = new GUI();
gui.loadGrid(args[0]);
}});
}
我看不出有任何理由删除所有标签
您所需要做的就是使用setText(…)来更改标签的文本。不需要删除所有标签,然后再重新添加。我看不出有任何理由删除所有标签
您所需要做的就是使用setText(…)来更改标签的文本。无需将它们全部删除,然后再重新添加。有时,当您只打算使用一个线程时,您会得到更多,并遇到错误线程的更新问题 对我来说,它发生在应用程序启动并开始准备GUI时。 同时,鼠标位于GUI所在的屏幕位置。
GUI发现鼠标已经在其空间中,可以与后台工作异步进行。将鼠标放在屏幕的一角会使问题消失。有时,当你只打算使用一个线程时,你会得到更多,并遇到错误线程的更新问题 对我来说,它发生在应用程序启动并开始准备GUI时。 同时,鼠标位于GUI所在的屏幕位置。
GUI发现鼠标已经在其空间中,可以与后台工作异步进行。把鼠标放在屏幕的一角,问题就消失了。我相信它被取消了主线程;我在上面发布了附加代码。我在上面的代码中没有看到您异常的原因。对不起,我不打算浏览“附加代码”的零碎部分。这就是为什么我推荐我们可以编译和运行的SSCCE。一旦它在我的代码编辑器中被(编译),我就会更仔细地查看代码。是的,一个SSCCE需要花费相当多的精力来创建,但这是花得很好的。我打赌如果OP这样做,他会自己发现错误的;我在上面发布了附加代码。我在上面的代码中没有看到您异常的原因。对不起,我不打算浏览“附加代码”的零碎部分。