Domanda

I have textfields which I would like to have display the total of several other textfields on the fly. I have never used Listeners before but after some research I found that DocumentListeners are probably what I am looking for. I've spent time reading trough related questions such as this and this and have also read through java docs but still feel shaky in my understanding and how I would accomplish what I need to do, mainly because I am using 1D and 2D arrays.

I want to record 3 different types of time (straight time, overtime, and double overtime) worked by 10 workers on each day of the week as well as the total.

To accomplish this, I created these variables:

private static final int NUMBER_OF_PERSONNEL = 10;
private static final int DAYS_OF_THE_WEEK = 7;

private JTextField OT2Field[][] = new JTextField[DAYS_OF_THE_WEEK][NUMBER_OF_PERSONNEL];
private JTextField OT1Field[][] = new JTextField[DAYS_OF_THE_WEEK][NUMBER_OF_PERSONNEL];
private JTextField STField[][] = new JTextField[DAYS_OF_THE_WEEK][NUMBER_OF_PERSONNEL];

private JTextField totalOT2Field[] = new JTextField [NUMBER_OF_PERSONNEL];
private JTextField totalOT1Field[] = new JTextField [NUMBER_OF_PERSONNEL];
private JTextField totalSTField[] = new JTextField [NUMBER_OF_PERSONNEL];

So, OT2Field[0][0] through OT2Field[6][0] will = totalOT2Field[0]

Would I need a DocumentListener for each type of time worked? Or could I have one DocumentListener and handle the different types and their data in the update methods? If the latter is possible, whats the best way to accomplish this? Please remember to keep in mind that I am new to Listeners.

È stato utile?

Soluzione

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.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top