我正在编写一个计算GPA的程序。它由几个面板组成。第一个小组 告诉用户指定课程数量,以便将Comboboxes(gradeCombo),(hourCombo)和Textfields动态添加到第二个面板。到目前为止一切都很好,但问题在于听众。在早期阶段,我为这些组合框中的每个元素单独注册了这些组合框的事件监听器,它产生了900行代码,但它工作正常,我的所有结果都是正确的。为了增强我的代码,我正在尝试编写for循环来注册组合框的事件,到目前为止,我无法成功。
我尝试将处理代码编写为匿名内部类,并作为单独的内部类,这是我的最后一次尝试:
for(i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler());
gradeCombo[i].addItemListener(new GradeHandler());
}
public class HoursHandler implements ItemListener
{
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String hour;
hour = (String) hourCombo[i].getSelectedItem();
currentHour[i]=Integer.parseInt(hour);
aquiredHours=aquiredHours+currentHour[i] prevHour[i];
prevHour[i]=currentHour[i];
}
}
}
public class GradeHandler implements ItemListener
{
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String grade;
grade=(String) gradeCombo[i].getSelectedItem();
switch(grade)
{
case "A+":
currentPoint[i]=5*currentHour[i];
break;
case "A":
currentPoint[i]= 4.75 * currentHour[i];
break;
case "B+":
currentPoint[i]= 4.5 * currentHour[i];
break;
case "B":
currentPoint[i]= 4 * currentHour[i];
break;
case "C+":
currentPoint[i]= 3.5 * currentHour[i];
break;
case "C":
currentPoint[i]= 3 * currentHour[i];
break;
case "D+":
currentPoint[i]= 2.5 * currentHour[i];
break;
case "D":
currentPoint[i]= 2 * currentHour[i];
break;
case "F":
currentPoint[i]= 1 * currentHour[i];
break;
}
aquiredPoints=aquiredPoints+currentPoint[i]-prevPoint[i];
prevPoint[i]=currentPoint[i];
}
}
}
我收到此声明的NullPointerException:
hour = (String) hourCombo[i].getSelectedItem();
并且一切都出错了,我的变量都没有更新,我无法计算GPA ..
答案 0 :(得分:1)
从发布的代码中很难说出那里有什么问题。但是,我假设i
被声明为实例变量。在这种情况下,循环for(i = 0; i<courseN;i++)
将更改此实例变量的值。之后,所有监听器将在内部使用i
以及在for
循环中收到的最后一个值。
为避免这种情况,您可以为每个侦听器实例声明一个实例变量。所以你可以改变你的监听器类:
public class HoursHandler implements ItemListener
{
private final int index;
HoursHandler(int index)
{
this.index = index;
}
@Override
public void itemStateChanged(ItemEvent event)
{
// Use the "index" here:
String hour = (String) hourCombo[index].getSelectedItem();
currentHour[index]=Integer.parseInt(hour);
...
}
}
(同样,为GradeHandler
引入这样的索引。)
然后,当您创建侦听器时,您可以将它引用的索引传递给每个实例:
// Note: "i" is declared here, and should NO longer
// be an instance variable!
for(int i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler(i)); // Use "i" as "index"
gradeCombo[i].addItemListener(new GradeHandler(i)); // Use "i" as "index"
}
我认为可能有一些更优雅的解决方案,但这只是一个可能的解决方案,完全基于您提供的代码。
答案 1 :(得分:0)
i
似乎是外部类中的成员字段。当你的听众被执行时,你的听众
hour = (String) hourCombo[i].getSelectedItem();
此语句将使用恰好在此外部类中的任何值i
。在您执行for
循环后,i
可能等于courseN
,除非在其他地方有其他更改内容。在任何情况下,它都不使用i
在设置监听器时所持有的值,因为你没有告诉它使用该值。
解决此问题的一种简单方法是通过为其提供您希望它们使用的索引来构建侦听器:
public class HoursHandler implements ItemListener
{
private final int index;
public HoursHandler(int index) {
this.index = index;
}
public void itemStateChanged(ItemEvent event)
{
if(event.getStateChange()==ItemEvent.SELECTED)
{
String hour;
hour = (String) hourCombo[index].getSelectedItem();
并在侦听器中的任何位置使用index
而不是i
。构造侦听器时,它将存储您想要的索引,然后代码将使用它而不是当前值i
。同样适用于GradeHandler
。然后
for(i = 0; i<courseN;i++)
{
hourCombo[i].addItemListener(new HoursHandler(i));
gradeCombo[i].addItemListener(new GradeHandler(i));
}
请注意,您希望侦听器使用的索引现在作为参数传递给侦听器的构造函数。
已编辑在索引成员上使用final
- 抄袭Marco13的好主意。