java - Java GUI 中的文档模型

标签 java swing document documentlistener

我的 GUI 中有两个 JTextAreas,每个 JTextArea 上都有一个 DocumentListener,例如,当我在文本区域编号 1 中键入 abc 时,该文档文本将以某种方式对其进行修改并将其输出到 JTextArea 2 的文档中。

使用我的 Listener 我可以获得源文档 我可以获得文本 我可以修改文本但是当我尝试将它放回文档时我得到一个错误

线程“AWT-EventQueue-0”java.lang.IllegalStateException 中的异常:尝试在通知中改变

请帮忙。

谢谢

这是一些代码:

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */

/**
 *
 * @author Maxi
 */
import java.awt.*;
import java.awt.event.*;
import javax.swing.event.*;
import javax.swing.*;
import javax.swing.text.*;

public class Test {

    static JFrame frame = new JFrame("CaesarEncipherGUI");
     static JPanel panel = new JPanel();
     static JTextArea area = new JTextArea(5,20);



     static JTextArea area1 = new JTextArea(5,20);


    static class MyDocumentListener2 implements DocumentListener {

    public void insertUpdate(DocumentEvent e) {
        updateLog(e,"");
    }
    public void removeUpdate(DocumentEvent e) {
        updateLog(e,"");

    }


    public void changedUpdate(DocumentEvent e) {

    }    


public void updateLog(DocumentEvent e, String action){


Document doc = (Document)e.getDocument();



try{


  System.out.println("Action detected  "+doc.getProperty("type"));

String text = doc.getText(0, doc.getLength());

doc.insertString(0, "hey", null); //heres the line that throws the error.



//mutation of text here

}catch (BadLocationException catchme2){}



}
}

        public static void main(String[] args){



            area.getDocument().addDocumentListener(new MyDocumentListener2());

         //initialize
         frame.setResizable(false);
         frame.setBounds(300, 300, 235, 400);
frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);



panel.add(area);
panel.add(area1);
frame.add(panel);
frame.setSize(235,400);
frame.setVisible(true);


     }



}

最佳答案

可能您正在尝试让 DocumentListener 更改它正在监听的同一个 Document 上的文本。根据 DocumentListener API 这是不允许的其中指出:

The DocumentEvent notification is based upon the JavaBeans event model. There is no guarantee about the order of delivery to listeners, and all listeners must be notified prior to making further mutations to the Document. This means implementations of the DocumentListener may not mutate the source of the event (i.e. the associated Document).

解决此问题的一种方法是将更改文档文本的方法放在 Runnable 中,并使用 SwingUtilities.invokeLater(...) 在 EDT 上对其进行排队。

另一种可能更好的解决方案是使用 DocumentFilter

DocumentListener 示例:

   static class MyDocumentListener2 implements DocumentListener {
      private boolean updating = false;

      public void insertUpdate(DocumentEvent e) {
         updateLog(e, "");
      }

      public void removeUpdate(DocumentEvent e) {
         updateLog(e, "");

      }

      public void changedUpdate(DocumentEvent e) {

      }

      public void updateLog(DocumentEvent e, String action) {
         if (updating) {
            return;
         }
         updating = true;

         final Document doc = (Document) e.getDocument();

         try {

            System.out.println("Action detected  " + doc.getProperty("type"));

            final String text = doc.getText(0, doc.getLength());

            SwingUtilities.invokeLater(new Runnable() {
               public void run() {
                  try {
                     doc.insertString(0, "hey", null);
                     updating = false;
                  } catch (BadLocationException e) {
                     e.printStackTrace();
                  }
               }
            });

         } catch (BadLocationException catchme2) {
            catchme2.printStackTrace();
         }

      }
   }

还有一个将所有文本转换为大写的 DocumentListener 和 DocumentFilter 示例:

import javax.swing.*;
import javax.swing.event.*;
import javax.swing.text.*;

public class Foo003 {
   private static final String ENTER = "enter";

   public static void main(String[] args) {
      final JTextArea myArea = new JTextArea(10, 20);
      final PlainDocument myDocument = (PlainDocument) myArea.getDocument();

      DocumentListener myDocumentListener = new DocumentListener() {
         private boolean changing = false;

         public void removeUpdate(DocumentEvent e) {}

         public void changedUpdate(DocumentEvent e) {
            toUpperCase(myArea, myDocument);
         }

         @Override
         public void insertUpdate(DocumentEvent e) {
            toUpperCase(myArea, myDocument);
         }

         private void toUpperCase(final JTextArea myArea,
               final PlainDocument myDocument) {
            if (changing) {
               return;
            }
            try {
               changing = true;
               final String text = myDocument
                     .getText(0, myDocument.getLength()).toUpperCase();
               SwingUtilities.invokeLater(new Runnable() {
                  public void run() {
                     myArea.setText(text);
                     changing = false;
                  }
               });
            } catch (BadLocationException e1) {
               e1.printStackTrace();
            }
         }

      };

      myDocument.addDocumentListener(myDocumentListener);

      JOptionPane.showMessageDialog(null, new JScrollPane(myArea),
            "With DocumentListener", JOptionPane.INFORMATION_MESSAGE);

      myDocument.removeDocumentListener(myDocumentListener);

      myArea.setText("");

      myDocument.setDocumentFilter(new DocumentFilter() {
         @Override
         public void insertString(FilterBypass fb, int offset, String text,
               AttributeSet attr) throws BadLocationException {
            text = text.toUpperCase();
            super.insertString(fb, offset, text, attr);
         }

         @Override
         public void replace(FilterBypass fb, int offset, int length,
               String text, AttributeSet attrs) throws BadLocationException {
            text = text.toUpperCase();
            super.replace(fb, offset, length, text, attrs);
         }
      });
      JOptionPane.showMessageDialog(null, new JScrollPane(myArea),
            "With DocumentFilter", JOptionPane.INFORMATION_MESSAGE);
   }
}

DocumentListeners 和 DocumentFilters 之间的一个主要区别(如果我错了,请有人纠正我!)是 DocumentListeners 在文档更新后触发,而 DocumentFilters 在更新之前触发。

关于java - Java GUI 中的文档模型,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/7439455/

相关文章:

java - Swing 中的可链接键盘处理程序

java - 如何在运行时在 Swing 中添加 JLabel?

java - append 到 XML 文件

javascript - 我可以将 document.getElementById 分配给 javascript 中的变量吗

确保页面已完全加载后,javascript单击按钮

java - 即使 Java 安装和路径变量设置没有问题,我也无法在命令行上运行类文件

Java Sockets 并发线程太慢

java - 为什么同步在第二个代码中不起作用?

java - 如何解决第 1 行第 "Incorrect integer value: ' 列的错误 'type_id' null'?

java - 嵌套 GridBagLayout - 如何将子级的列与父级的列对齐