Question

Hi I have problem with my documentlistener. Program stop working after I insert value into textfield. This program should XOR 1st row of textfields with 2nd row of textfields and put result into 3rd row of textfields

package opa.beta1;

import java.awt.BorderLayout;
import java.math.BigInteger;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.SwingUtilities;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class TextFieldEvent {

    JTextField arrayIV[] = new JTextField[8];
    JTextField plaintextArray[] = new JTextField[8];
    JTextField ciphertextArray[] = new JTextField[8];
    JFrame frame = new JFrame("OPA");
    JPanel panel1 = new JPanel();
    JPanel panel2 = new JPanel();
    JPanel panel3 = new JPanel();

    public void setJPanel(JTextField array[], JPanel container, String s) {
        for (int i = 0; i < 8; i++) {
            array[i] = new JTextField(s, 4);
            array[i].getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent de) {
                    setCiphertext();
                }

                @Override
                public void removeUpdate(DocumentEvent de) {
                    setCiphertext();
                }

                @Override
                public void changedUpdate(DocumentEvent de) {
                    setCiphertext();
                }
            });
            container.add(array[i]);
        }
    }

    public String setXORText(JTextField textfield1, JTextField textfield2) {
        String okno1, okno2;
        okno1 = textfield1.getText();
        okno2 = textfield2.getText();
        if (okno1.equals("")) {
            return okno2;
        }
        BigInteger pom1 = new BigInteger(okno1, 16);
        if (okno2.equals("")) {
            return okno1;
        }
        BigInteger pom2 = new BigInteger(okno2, 16);
        BigInteger res = pom1.xor(pom2);
        String s = res.toString(16);
        return s;
    }

    public String setXORText(JTextField pole1[], JTextField pole2[], int i) {

        String okno1 = pole1[i].getText();
        String okno2 = pole2[i].getText();
        if (okno1.equals("")) {
            return pole2[i].getText();
        }
        BigInteger pom1 = new BigInteger(okno1, 16);
        if (okno2.equals("")) {
            return pole1[i].getText();
        }
        BigInteger pom2 = new BigInteger(okno2, 16);
        BigInteger res = pom1.xor(pom2);
        String s = res.toString(16);
        return s;
    }

    public void setCiphertext() {
        //textfield3.setText(setXORText(textfield1, textfield2));
        for (int i = 0; i < 8; i++) {
            ciphertextArray[i].setText(setXORText(arrayIV, plaintextArray, i));
        }
    }

    public TextFieldEvent() {
        setJPanel(arrayIV, panel1, "1a");
        setJPanel(plaintextArray, panel2, "1b");
        setJPanel(ciphertextArray, panel3, "1");

        frame.add(panel1, BorderLayout.NORTH);
        frame.add(panel2, BorderLayout.CENTER);
        frame.add(panel3, BorderLayout.SOUTH);

        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.pack();
        frame.setVisible(true);
        frame.setSize(675, 275);
        frame.setResizable(false);
    }

    public static void main(String[] args) {
        SwingUtilities.invokeLater(new Runnable() {
            @Override
            public void run() {
                new TextFieldEvent();
            }
        });

    }
}

Stacktrace

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338) at javax.swing.text.AbstractDocument.replace(AbstractDocument.java:659) at javax.swing.text.JTextComponent.setText(JTextComponent.java:1718) at opa.beta1.TextFieldEvent.setCiphertext(TextFieldEvent.java:82) at opa.beta1.TextFieldEvent$1.removeUpdate(TextFieldEvent.java:33)
Was it helpful?

Solution

This line

setJPanel(ciphertextArray, panel3, "1");

also adds a DocumentListener to every element of the ciphertextArray TextField. So every time the value of one of your cipher text TextFields changes, the method setCipherText() is invoked.

This leads to the following sequence:

  1. You enter a new value in one of the TextFields of arrayIV or plainTextArray
  2. setCipherText() is invoked
  3. setCipherText() changes the value of a cipher text TextField
  4. setCipherText() is again invoked (explanation above). Go back to 2.

Thats why you get the IllegalStateException.

So the solution is to do NOT add a DocumentListener to the TextFields in your ciphertextArray.

Solution could be implemented as follows:

public void setJPanel(JTextField array[], JPanel container, String s, boolean docListener) {
    for (int i = 0; i < 8; i++) {
        array[i] = new JTextField(s, 4);
        if (docListener) {
            array[i].getDocument().addDocumentListener(new DocumentListener() {
                @Override
                public void insertUpdate(DocumentEvent de) {
                    setCiphertext();
                }

                @Override
                public void removeUpdate(DocumentEvent de) {
                    setCiphertext();
                }

                @Override
                public void changedUpdate(DocumentEvent de) {
                    setCiphertext();
                }
            });
        }
        container.add(array[i]);
    }
}

[...]

    setJPanel(arrayIV, panel1, "1a", true);
    setJPanel(plaintextArray, panel2, "1b", true);
    setJPanel(ciphertextArray, panel3, "1", false);

OTHER TIPS

Wrap the setCiphertext(); in your DocumentListener in SwingUtilities.invokeLater

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top