【问题标题】:JTextFields and DocumentListenersJTextFields 和 DocumentListeners
【发布时间】:2017-01-04 23:44:13
【问题描述】:

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

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

对于这种特殊情况,KeyListener 不可靠,我拒绝使用按钮,因为我喜欢 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");
        }
    }


}

【问题讨论】:

    标签: java jtextfield documentlistener


    【解决方案1】:

    您遇到的问题是,由于两个JTextFields 需要同步,每个字段的DocumentListener 需要更新另一个字段。但是,该更新会导致另一个 DocumentListener 尝试更新第一个字段,从而导致抛出 IllegalStateException,因为在执行 DocumentListener 时,有些东西正在尝试修改该字段。

    解决方案是在针对该字段执行DocumentListener 时阻止对setText(String) 的调用。这可以通过boolean 变量来完成。以下是DocumentListeners 之一的代码:

    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 变量)。现在,当在textFieldADocumentListener 中触发方法时,会设置一个标志以指示不使用textFieldA.setText(String)。我们还看到了在设置blockB 时如何阻止textFieldB.setText(String)DocumentListener 对应于 textFieldB 看起来差不多。

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

    【讨论】:

    • 成功了!!!非常感谢老兄......我希望得到这样的答案,而不是常规的“使用文档过滤器”。正如您可能已经发现的那样,我喜欢测试一些东西,即使它们没有必要合法。
    【解决方案2】:

    我不完全确定这是“正确”的做法,但我所做的只是将相同的 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());
    

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

    【讨论】:

      猜你喜欢
      • 2013-06-02
      • 2017-02-10
      • 1970-01-01
      • 1970-01-01
      • 2013-03-14
      • 1970-01-01
      • 2011-05-25
      • 2013-09-22
      • 2017-11-25
      相关资源
      最近更新 更多