2013-03-04 22 views
8

Moim celem jest zaimplementowanie niebieskiego kolorowania słów kluczowych napisanych przez użytkownika do JTextPane. W ten sposób mój kod wygląda tak:Wyjątek "Próba mutacji powiadomień"

private class DocumentHandler implements DocumentListener { 

     @Override 
     public void changedUpdate(DocumentEvent ev) { 
     } 

     @Override 
     public void insertUpdate(DocumentEvent ev) { 
      highlight(); 
     } 

     @Override 
     public void removeUpdate(DocumentEvent ev) { 
      highlight(); 
     } 

     private void highlight() { 
      String code = codePane.getText(); 
      SimpleAttributeSet defSet = new SimpleAttributeSet(); 
      StyleConstants.setForeground(defSet, Color.BLACK); 
      doc.setCharacterAttributes(0, code.length(), defSet, true); 
      SimpleAttributeSet set = new SimpleAttributeSet(); 
      StyleConstants.setForeground(set, Color.BLUE); 
      for (String keyword : keywords) { 
       Pattern pattern = Pattern.compile(keyword + "(\\[\\])*"); 
       Matcher matcher = pattern.matcher(code); 
       while (matcher.find()) { 

        //Just for test 
        System.out.print("Start index: " + matcher.start()); 
        System.out.print(" End index: " + matcher.end()); 
        System.out.println(" Found: " + matcher.group()); 

        doc.setCharacterAttributes(matcher.start(), keyword.length(), set, true); 
       } 
      } 
     } 
    } 

Po wpisaniu czegokolwiek w okienku pojawia się:

Exception in thread "AWT-EventQueue-0" java.lang.IllegalStateException: Attempt to mutate in notification 
    at javax.swing.text.AbstractDocument.writeLock(AbstractDocument.java:1338) 
    at javax.swing.text.DefaultStyledDocument.setCharacterAttributes(DefaultStyledDocument.java:500) 
    at jnotepad.MainPanel$DocumentHandler.highlight(MainPanel.java:121) 
    at jnotepad.MainPanel$DocumentHandler.insertUpdate(MainPanel.java:108) 
    at javax.swing.text.AbstractDocument.fireInsertUpdate(AbstractDocument.java:202) 
    at javax.swing.text.AbstractDocument.handleInsertString(AbstractDocument.java:749) 

Jak rozwiązać mój problem? Może powinienem użyć czegoś innego niż DocumentListener?

Odpowiedz

14

Musisz wywołać zmiany w dokumencie z wątku Event Traatcher.

Spróbuj tego:

private void highlight() { 

    Runnable doHighlight = new Runnable() { 
     @Override 
     public void run() { 
      // your highlight code 
     } 
    };  
    SwingUtilities.invokeLater(doHighlight); 
} 
+4

Problem nie jest to, że 'highlight()' jest wykonywany z niewłaściwym wątku. Zamiast tego, 'invokeLater (Runnable)' rozwiązuje problem, ponieważ odkłada wykonanie do czasu zwolnienia blokady dokumentu. –

0

miałem ten sam problem, rozwiązać go za pomocą tego:

expiration_timeTF.getDocument().addDocumentListener(
      new DocumentListener() { 
       @Override 
       public void removeUpdate(DocumentEvent e) { 
        System.out.println("remove"); 
       } 

       private void assistDateText() { 
        Runnable doAssist = new Runnable() { 
         @Override 
         public void run() { 
          // when input "2013",will add to "2013-";when 
          // input "2013-10",will add to "2013-10-" 
          String input = expiration_timeTF.getText(); 
          if (input.matches("^[0-9]{4}")) { 
           expiration_timeTF.setText(input + "-"); 
          } else if (input.matches("^[0-9]{4}-[0-9]{2}")) { 
           expiration_timeTF.setText(input + "-"); 
          } 
         } 
        }; 
        SwingUtilities.invokeLater(doAssist); 
       } 

       @Override 
       public void insertUpdate(DocumentEvent e) { 
        // System.out.println("insert"); 
        assistDateText(); 
       } 

       @Override 
       public void changedUpdate(DocumentEvent e) { 
        // System.out.println("change"); 
       } 
      });