JTextFields和DocumentListeners

时间:2016-08-29 02:48:28

标签: java jtextfield documentlistener

我想要两个文本字段(从现在开始A和B)共享与用户输入相同的内容。我可以将另一个镜子(B镜子A)或相反镜子(镜子B)制成一个镜子。但是当我保留两个DocumentListener时,执行开始抛出异常。

根据Oracle的文档,我不能使用DocumentListener来改变Listener本身内部文档的内容。我觉得很奇怪,因为我已经在第一种情况下做了(B镜子A)或相反的情况。无论如何,代码仍然是"工作"但是每触发两次事件就会抛出异常。

KeyListeners对于这种特殊情况不可靠,我拒绝使用按钮,因为我喜欢DocumentListener给出的实时外观。

有什么建议吗?

这是我的代码:

import java.awt.GridBagConstraints;
import java.awt.GridBagLayout;
import javax.swing.JFrame;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import javax.swing.event.DocumentEvent;
import javax.swing.event.DocumentListener;

public class Mirror {
    private JTextField oriText;
    private JTextField mirrorText;
    private static int debugCounter; //Counts the times an Event is Triggered.

    public static void main(String[] args) {
        Mirror gui = new Mirror();
        gui.build();
    }

    public void build(){

        JFrame frame = new JFrame();
        JPanel panel = new JPanel();
        panel.setLayout(new GridBagLayout());
        GridBagConstraints c = new GridBagConstraints();
        frame.getContentPane().add(panel);
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        c.gridx = 0;
        c.gridy = 0;
        JLabel original = new JLabel("Original");
        panel.add(original, c);

        c.gridy = 1;
        oriText = new JTextField(10);
        panel.add(oriText,c);


        c.gridy = 2;
        JLabel mirror = new JLabel("Mirror");
        panel.add(mirror, c);

        c.gridy = 3;
        mirrorText = new JTextField(10);
        panel.add(mirrorText, c);           
        mirrorText.getDocument().addDocumentListener(new MyDocumentListenerII()); // Comment this line to see only the 1st Case (B mirrors A)
        oriText.getDocument().addDocumentListener(new MyDocumentListener()); // Comment this line to see only the 2nd Case (A mirrors B) 


        frame.pack();
        frame.setVisible(true);
    }

    class MyDocumentListener implements DocumentListener{

        @Override
        public void changedUpdate(DocumentEvent e) {
            //Does nothing.

        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            mirror();
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            mirror();
        }


    }

    class MyDocumentListenerII implements DocumentListener{

        @Override
        public void changedUpdate(DocumentEvent e) {
            // Does nothing.
        }

        @Override
        public void insertUpdate(DocumentEvent e) {
            mirror1();
        }

        @Override
        public void removeUpdate(DocumentEvent e) {
            mirror1();
        }

    }

    public void mirror(){
        if (!oriText.getText().equals(mirrorText.getText())){ //Without this each Event trigger the other in some sort of Paradoxical cycle. 
            mirrorText.setText(oriText.getText());
            debugCounter++;
            System.out.println(debugCounter+" events triggered");
        }
    }

    public void mirror1(){
        if (!mirrorText.getText().equals(oriText.getText())){
            oriText.setText(mirrorText.getText());
            debugCounter++;
            System.out.println(debugCounter+" events triggered");
        }
    }


}

2 个答案:

答案 0 :(得分:0)

我不完全确定这是'正确'的方法,但我所做的只是将Document添加到每个JTextField

以下是我的初始化程序中的相关部分:

textFieldA = new JTextField();
textFieldA.setBounds(10, 11, 414, 20);
textFieldA.setColumns(10);

textFieldB = new JTextField();
textFieldB.setBounds(10, 42, 414, 20);
textFieldB.setColumns(10);
textFieldB.setDocument(textFieldA.getDocument());

现在JTextField都有相同的文档,所以它们不能不同。

答案 1 :(得分:0)

您遇到的问题是,由于两个JTextField都需要同步,因此每个字段的DocumentListener都需要更新另一个字段。但是,该更新会导致另一个DocumentListener尝试更新第一个字段,导致抛出IllegalStateException,因为正在尝试修改该字段,而DocumentListener正在执行该字段。 / p>

解决方案是在为该字段执行setText(String)时阻止对DocumentListener的调用。这可以使用boolean个变量来完成。以下是其中一个DocumentListener s的代码:

textFieldA.getDocument().addDocumentListener(new DocumentListener() {
  @Override
  public void removeUpdate (DocumentEvent e) {
    blockA = true;
    if (!blockB) textFieldB.setText(textFieldA.getText());
    blockA = false;
  }
  @Override
  public void insertUpdate (DocumentEvent e) {
    blockA = true;
    if (!blockB) textFieldB.setText(textFieldA.getText());
    blockA = false;
  }
  @Override
  public void changedUpdate (DocumentEvent e) {
    blockA = true;
    if (!blockB) textFieldB.setText(textFieldA.getText());
    blockA = false;
  }
});

其中blockAblockBboolean个实例字段(或方法中可能final个变量)。现在,当方法在textFieldA的{​​{1}}中触发时,会设置一个标记以指示不使用DocumentListener。我们还会看到textFieldA.setText(String)设置时textFieldB.setText(String)被阻止的方式。 blockB的{​​{1}}看起来大致相同。

现在,DocumentListener内的呼叫期间不会设置textFieldB,其他字段也是如此。无论如何,这样的调用将是多余的:每个字段的文本在那时都是相同的。