解决这个问题的一个简单方法是编写一个实现 DocumentListener 的类,该类知道应该总结哪些文本字段以及需要更新的总文本字段。
在下面的实现中,我只是假设 OT 表示为十进制数。
public class OvertimeSumListener implements DocumentListener {
private JTextField[] otFields;
private JTextField total;
public OvertimeSumListener(JTextField[] otFields, JTextField total) {
this.otFields = otFields;
this.total = total;
}
public void calculateTotal() {
double sum = 0;
for (JTextField otField : otFields) {
String text = otField.getText();
try {
sum += Double.parseDouble(text);
} catch (NumberFormatException e) {
// not a number - ignore
}
}
total.setText(String.format("%.2f", sum));
}
public void insertUpdate(DocumentEvent e) {
calculateTotal();
}
public void removeUpdate(DocumentEvent e) {
calculateTotal();
}
public void changedUpdate(DocumentEvent e) {
calculateTotal();
}
}
在初始化侦听器并将它们绑定到您的文本字段时,如果您将 2D 数组从 [DAYS_OF_THE_WEEK][NUMBER_OF_PERSONNEL] 翻转到 [NUMBER_OF_PERSONNEL][DAYS_OF_THE_WEEK] 会更容易,即像这样:
private JTextField OT2Field[][] = new JTextField[NUMBER_OF_PERSONNEL][DAYS_OF_THE_WEEK];
private JTextField OT1Field[][] = new JTextField[NUMBER_OF_PERSONNEL][DAYS_OF_THE_WEEK];
private JTextField STField[][] = new JTextField[NUMBER_OF_PERSONNEL][DAYS_OF_THE_WEEK];
最后,一些初始化和绑定监听器到文本字段的方法:
private void initializeAllTimeFields() {
for (int i = 0; i < NUMBER_OF_PERSONNEL; i++) {
totalOT1Field[i] = initializeTimeFields(OT1Field[i]);
totalOT2Field[i] = initializeTimeFields(OT2Field[i]);
totalSTField[i] = initializeTimeFields(STField[i]);
}
}
private JTextField initializeTimeFields(JTextField[] timeFields) {
JTextField totalField = new JTextField();
totalField.setEditable(false);
OvertimeSumListener listener = new OvertimeSumListener(timeFields, totalField);
for (int i = 0; i < timeFields.length; i++) {
timeFields[i] = new JTextField();
timeFields[i].getDocument().addDocumentListener(listener);
}
return totalField;
}
编辑(根据请求,参见 cmets):初始化代码演练
注意:我重命名了初始化方法,以便在解释中更容易区分两者。
初始化代码的总体思路是初始化所有属于同一个方法的字段;即 OT 字段和相应的总字段。这里的观察结果是,对于每个人和,每个时间字段(OT1、OT2、ST)的摘要应该是分开的。所以属于一起的字段是时间字段的一维数组和一个总字段;这正是 OvertimeSumListener 中包含的内容。
initializeAllTimeFields 方法是人员的简单循环,它调用 initializeTimeFields 方法 3 次(每种时间类型一次)为该人员初始化该类型的字段。
请注意,时间字段被定义为数组数组。所以OT1Field 的类型是JTextField[][]。在循环中,OT1Field[i] 的类型为JTextField[],即内部数组。由于内部数组很容易获得,因此如果内部数组具有“星期几”维度,而外部具有“人员”维度,则代码会大大简化;这就是翻转数组的原因。
第一种方法initializeAllTimeFields是人员的简单迭代。对于每次迭代(即每个人员),为三种时间类型中的每一种调用第二种方法。
第二种方法,initializeTimeFields 将“星期几”的数组用于一个人和一个时间类型。数组值用新的JTextField 对象初始化,并返回一个新的JTextField 对象作为总数。它还创建一个新的OvertimeSumListener 并将其添加到每个数组元素(但不是总数)。
此方法的签名旨在简化代码。由于java中的数组是作为对象引用传递的,所以当修改initializeTimeFields中的一维数组时,会修改原始数组的内容。此外,在此方法中创建和初始化总计字段的新对象,并返回结果总计对象,以便可以将总计数组的正确数组元素分配给该值。