Как установить текст для JTextField из другого класса с помощью DocumentFIlter?

В следующем примере я создал два поля texField. При записи в первом текстовом поле, если пробел или число введено пользователем, должно отображаться сообщение в другом текстовом поле_1. Но как только пользователь ввел число/пробел, он выдал java.lang.NullPointerException.

public class NewDemo extends JFrame {
private JPanel p1;
private JTextField textField,textField_1;
public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
        public void run() {
            try {
                NewDemo frame = new NewDemo();
                frame.setVisible(true);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
    });
}


public NewDemo() {
    setTitle("New Demo");
    setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    setBounds(100, 100, 500, 500);
    p1 = new JPanel();
    p1.setBorder(new EmptyBorder(5, 5, 5, 5));
    setContentPane(p1);
    p1.setLayout(null);

    textField = new JTextField();
    textField.setBounds(70, 71, 86, 20);
    p1.add(textField);
    textField.setColumns(10);

    JLabel lblNewLabel = new JLabel("");
    lblNewLabel.setBounds(70, 96, 86, 14);
    p1.add(lblNewLabel);

    textField_1 = new JTextField();
    textField_1.setBounds(204, 71, 86, 20);
    p1.add(textField_1);
    textField_1.setColumns(10);

     System.out.println("before calling");

     ((AbstractDocument) textField.getDocument()).setDocumentFilter(new MyDocumentFilter());

        System.out.println("AfterCalling");
}
public JTextField getTextField_1() {
    return textField_1;
}}

Вот второй класс MyDocumentFilter, где ошибка java.lang.NullPointerException возникает в блоке else метода replace.

class MyDocumentFilter extends DocumentFilter {
private NewDemo n1;
@Override
public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {
    System.out.println("Starting: replace Method");


    for (int n = string.length(); n > 0; n--) 
        char c = string.charAt(n - 1);
        System.out.println(c);
        if (Character.isAlphabetic(c)) {
          System.out.println("In if: replace method");
            super.replace(fb, i, i1, String.valueOf(c), as);
        } else {
            System.out.println("Not allowed:BEFORE");
            n1.getTextField_1().setText("not allowed");//***HERE IS THE ERROR
            System.out.println("Not allowed:AFTER");

        }
    }
}

@Override
public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
    System.out.println("In :remove method");
    super.remove(fb, i, i1);
}

@Override
public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
   System.out.println("In: insterString Method");
    super.insertString(fb, i, string, as);
 }}

person AshwinK    schedule 14.03.2015    source источник
comment
Не изменяйте состояние компонентов из DocumentFilter, это не входит в обязанности фильтра. Если вы хотите знать, когда фильтр выходит из строя, пусть фильтр вызывает какое-то событие, которое вы можете прослушивать и предпринимать соответствующие действия.   -  person MadProgrammer    schedule 15.03.2015
comment
@MadProgrammer: я попытался включить ваши предложения в свой ответ. Спасибо! Редактировать: и вы тоже! 1+   -  person Hovercraft Full Of Eels    schedule 15.03.2015


Ответы (2)


Вашему DocumentFilter нужна ссылка на отображаемый объект NewDemo GUI. Не просто создавайте экземпляр new NewDemo, как предложил другой, поскольку это создаст неотображаемый отдельный экземпляр, а скорее передаст соответствующую отображаемую ссылку.

e.g.,

  ((AbstractDocument) textField.getDocument())
        .setDocumentFilter(new MyDocumentFilter(this)); //!!

а также

class MyDocumentFilter extends DocumentFilter {
   private NewDemo n1;

   public MyDocumentFilter(NewDemo n1) {
      this.n1 = n1;
   }

Но да, также следуйте любым рекомендациям от MadProgrammer, поскольку он знает свой Swing и Java вдоль и поперек. Также вам следует избегать использования нулевого макета и использования setBounds(...) для размещения компонентов, поскольку это делает очень негибкие графические интерфейсы, которые, хотя они могут хорошо выглядеть на одной платформе, выглядят ужасно на большинстве других платформ или разрешений экрана, и их очень трудно обновлять и поддерживать.


Редактировать, используя предложение MadProgrammer, подумайте о том, чтобы разрешить вашему графическому интерфейсу добавлять PropertyChangeListener в DocumentFilter. Таким образом, любой класс может прослушивать изменения в «состоянии» DocumentFilter. Здесь я создал логическое состояние, называемое «действительным», которое уведомляет слушателей каждый раз, когда изменяется логическая переменная.

Например:

import java.awt.*;
import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;

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

public class NewDemo extends JPanel {
   private static final long serialVersionUID = 1L;
   private JTextField textField, textField_1;

   private static void createAndShowGui() {
      NewDemo mainPanel = new NewDemo();

      JFrame frame = new JFrame("New Demo");
      frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
      frame.getContentPane().add(mainPanel);
      frame.pack();
      frame.setLocationByPlatform(true);
      frame.setVisible(true);
   }

   public static void main(String[] args) {
      SwingUtilities.invokeLater(new Runnable() {
         public void run() {
            createAndShowGui();
         }
      });
   }

   public NewDemo() {
      setLayout(new GridLayout(1, 0, 5, 5));
      setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
      textField = new JTextField();
      textField.setColumns(10);
      add(textField);

      textField_1 = new JTextField();
      textField_1.setColumns(10);
      add(textField_1);

      MyDocumentFilter docFilter = new MyDocumentFilter(); // !!

      ((AbstractDocument) textField.getDocument()).setDocumentFilter(docFilter); // !!
      docFilter.addPropertyChangeListener(MyDocumentFilter.VALID,
            new PropertyChangeListener() {

               @Override
               public void propertyChange(PropertyChangeEvent evt) {
                  String text = ((Boolean) evt.getNewValue()) ? "Allowed"
                        : "Not Allowed";
                  textField_1.setText(text);
               }
            });
   }
}

class MyDocumentFilter extends DocumentFilter {
   public static final String VALID = "valid";
   private SwingPropertyChangeSupport pcSupport = new SwingPropertyChangeSupport(
         this);
   private boolean valid = true;

   @Override
   public void replace(FilterBypass fb, int i, int i1, String string,
         AttributeSet as) throws BadLocationException {    
      for (int n = string.length(); n > 0; n--) {
         char c = string.charAt(n - 1);
         System.out.println(c);
         if (Character.isAlphabetic(c)) {
            super.replace(fb, i, i1, String.valueOf(c), as);
            setValid(true);
         } else {
            setValid(false);
         }
      }
   }

   @Override
   public void remove(FilterBypass fb, int i, int i1)
         throws BadLocationException {
      super.remove(fb, i, i1);
   }

   @Override
   public void insertString(FilterBypass fb, int i, String string,
         AttributeSet as) throws BadLocationException {
      super.insertString(fb, i, string, as);
   }

   public boolean isValid() {
      return valid;
   }

   public void setValid(boolean valid) {
      boolean oldValue = this.valid;
      boolean newValue = valid;
      this.valid = valid;
      pcSupport.firePropertyChange(VALID, oldValue, newValue);
   }

   public void addPropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.addPropertyChangeListener(listener);
   }

   public void removePropertyChangeListener(PropertyChangeListener listener) {
      pcSupport.removePropertyChangeListener(listener);
   }

   public void addPropertyChangeListener(String propertyName,
         PropertyChangeListener l) {
      pcSupport.addPropertyChangeListener(propertyName, l);
   }

   public void removePropertyChangeListener(String propertyName,
         PropertyChangeListener l) {
      pcSupport.removePropertyChangeListener(propertyName, l);
   }
}
person Hovercraft Full Of Eels    schedule 14.03.2015
comment
Спасибо. Оно работает. Но не могли бы вы объяснить мне немного больше о том, почему мы использовали метод public MyDocumentFIlter(NewDemo n1) и как он здесь работает? Спасибо точно не воспользуюсь. Но вместо setBounds и null layout что мне использовать? Пожалуйста, приведите любой пример, поэтому я буду следовать ему и мне будет лучше понять. Еще раз спасибо. - person AshwinK; 15.03.2015
comment
Нужно немного больше помощи от вас. Как и в этой программе, когда я собираюсь ввести числовое значение или пробел, оно показывает НЕ РАЗРЕШЕНО (но это постоянно). Если я хочу сделать это как после нажатия числа/пробела, оно должно показывать НЕ РАЗРЕШЕНО, но после этого, если я нажму любой символ тогда НЕ РАЗРЕШЕНО должно быть удалено. Как это сделать ? Не могли бы вы отредактировать его в приведенном выше коде? Спасибо @HovercraftFullOfEels - person AshwinK; 15.03.2015
comment
Оки. Еще раз, спасибо. На самом деле я мало что знаю о PropertyChangeListener. Но будет проходить через java.docs, если возникнут какие-либо проблемы с пониманием, опубликует комментарий. - person AshwinK; 15.03.2015
comment
@ user1995161: Также, пожалуйста, посмотрите и проголосуйте за альтернативный код прослушивателя MadProgrammer. Он знает о свинге больше, чем вы или я когда-либо узнаем. - person Hovercraft Full Of Eels; 15.03.2015
comment
@HovercraftFullOfEels да, конечно. - person AshwinK; 15.03.2015

DocumentFilter не несет ответственности за изменение состояния пользовательского интерфейса. Вместо этого он должен предоставлять уведомление об ошибке состояния (или что-то еще, что вы хотите знать) и позволять делегату принимать решения о том, что следует делать.

public interface DocumentFilterListener {
    public void documentFilterValidationFailed(DocumentFilter filter, String message);
}

public class MyDocumentFilter extends DocumentFilter {
    private DocumentFilterListener filterListener;

    public MyDocumentFilter(DocumentFilterListener filterListener) {
        this.filteristener = filterListener;
    }

    @Override
    public void replace(FilterBypass fb, int i, int i1, String string, AttributeSet as) throws BadLocationException {
        System.out.println("Starting: replace Method");


        for (int n = string.length(); n > 0; n--) 
            char c = string.charAt(n - 1);
            System.out.println(c);
            if (Character.isAlphabetic(c)) {
              System.out.println("In if: replace method");
                super.replace(fb, i, i1, String.valueOf(c), as);
            } else if (filterListener != null) {
                System.out.println("Not allowed:BEFORE");
                filterListener.documentFilterValidationFailed(this, "not allowed");
                System.out.println("Not allowed:AFTER");

            }
        }
    }

    @Override
    public void remove(FilterBypass fb, int i, int i1) throws BadLocationException {
        System.out.println("In :remove method");
        super.remove(fb, i, i1);
    }

    @Override
    public void insertString(FilterBypass fb, int i, String string, AttributeSet as) throws BadLocationException {
       System.out.println("In: insterString Method");
        super.insertString(fb, i, string, as);
     }
}

Тогда вы бы просто реализовали требования интерфейса

((AbstractDocument) textField.getDocument()).setDocumentFilter(
    new MyDocumentFilter(new DocumentFilterListener() {
        public void documentFilterValidationFailed(DocumentFilter filter, String message) {
            getTextField_1().setText(message);
        }
    }));

В качестве примера.

person MadProgrammer    schedule 14.03.2015
comment
Оки. Звучит здорово. Вы, ребята, чертовски быстро программируете. Между чем я должен сослаться, чтобы я был хорош в таких вещах, как DocumentListener, Filter, Validation и прослушиватель свойств? Большое спасибо за ваш ответ и отличный ответ на мой вопрос. Я думаю, что потребуется больше 2-3 часов, чтобы понять вещи, опубликованные вами и @Hovercraft. - person AshwinK; 15.03.2015