2011-09-16 37 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