2011-09-16 32 views
1

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

与我的监听器我可以获取源文档得到一个错误

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

PLE帮助。

感谢

下面是一些代码:

/* 
* 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); 


    } 



} 
+0

那么,如果侦听器在文档1上并且您尝试更改文档2中的文本,是否会发生此错误?或者仅当您尝试更改正在侦听的相同文档中的文本时。我猜想这将是后者,并且该问题在DocumentListener API中的“不保证订单...”部分有详细描述。一种解决方案是将代码封装在Runnable中,并通过'SwingUtilities.invokeLater(...)'将其排列在EDT上。 –

+0

从我在线阅读的内容看来,您并不认为要更改文档侦听器中的文档文本。然后,我会在哪里执行文档中的文本更改。 – user541597

+0

同样,您可以通过在EDT上排队更改来完成此操作。另一个也许更好的解决方案是使用DocumentFilter。 –

回答

4

有可能你是想拥有的DocumentListener改变,这是听同一个文档中的文本。这是不允许的,按照DocumentListener API其中规定:

DocumentEvent通知基于JavaBeans事件模型。无法保证传递给监听者的顺序,并且在对文档进行进一步突变之前必须通知所有监听者。这意味着DocumentListener的实现可能不会改变事件的来源(即关联的文档)。

解决此问题的一个方法是将您的方法更改为Runnable中的文档的文本并将其排列在EDT上,并使用SwingUtilities.invokeLater(...)

另一个解决方案,或许更好,是使用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在更新之前触发。

+0

您能否给我一些示例代码来完成此操作。此外,我正在尝试更改的文档是不同的文档,但得到相同的错误。 – user541597

+0

如果你创建一个显示你的问题的[sscce](http://sscce.org),我会尝试修改它。 –

+0

我已经在上面添加了ssccee。 – user541597