Модель документа в графическом интерфейсе Java - PullRequest
1 голос
/ 16 сентября 2011

У меня есть два JTextAreas в моем графическом интерфейсе, и у меня есть DocumentListener на каждом JTextArea, что я пытаюсь сделать, например, когда я набираю abc в текстовой области номер 1, он будет принимать этот документ каким-то образом изменить его и выведите его в Документ для JTextArea 2.

с помощью моего прослушивателя я могу получить исходный документ, я могу получить текст, я могу изменить текст, но когда я пытаюсь вставить его обратно в документ, я получаю ошибку

Исключение в потоке "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);


     }



}

1 Ответ

4 голосов
/ 16 сентября 2011

Вероятно, вы пытаетесь заставить 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 запускаются до его обновления.

...