One simple way to solve this is to write a class the implements DocumentListener
that knows which textfields that should be summarized and the total textfield it needs to update.
In the implementation below I've just assumed that the OT is represented as a decimal number.
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();
}
}
When initializing the listeners and binding them to your textfields it is easier if you flip your 2D arrays from [DAYS_OF_THE_WEEK][NUMBER_OF_PERSONNEL]
to [NUMBER_OF_PERSONNEL][DAYS_OF_THE_WEEK]
, i.e. like this:
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];
Finally, some methods to initialize and bind listeners to textfields:
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;
}
Edit (by request, see comments): Walkthrough of the initialization code
Note: I renamed the initialization methods to make it easier to distinguish between the two in explanation.
The general idea of initialization code is to initialize all fields that belong together in the same method; i.e. the OT fields and the corresponding total field. The observation here is that the summary should be separate for each person and for each of the time fields (OT1, OT2, ST). So the fields that belong together is a one-dimensional array of time fields and one total field; which is exactly what was included in the OvertimeSumListener
.
The initializeAllTimeFields
method is a simple loop over the personnel that calls the initializeTimeFields
method three times (one for each time type) to initialize the fields of that type for that person.
Note that the time fields are defined as array of arrays. So the type of OT1Field
is JTextField[][]
. In the loop, the type of OT1Field[i]
is JTextField[]
, i.e. the inner array. Since it is so easy to obtain the inner array, the code is much simplified if the inner array has the "days of the week" dimension and the outer has the "personnel" dimension; which was the reason for flipping the arrays.
The first method, initializeAllTimeFields
is a simple iteration of the personnel. For each iteration (i.e. each of the personnel) the second method is called for each of the three time types.
The second method, initializeTimeFields
takes the array of "days of the week" for one person and one time type. The array values are initialized with new JTextField
objects and a new JTextField
object for the total is returned. It also creates a new OvertimeSumListener
and adds it to each of the array elements (but not to the total).
The signature of this method was designed to simplify the code. Since arrays in java are passed as object references, the contents of the original array will be modified when modifications are made to the single dimension array in initializeTimeFields
. Further, a new object for the total field is created and initialized in this method and the resulting total object is returned so that the correct array element of the total array can be assigned to this value.