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

В следващия пример създадох две texFields. Докато пишете в първия текстов файл, ако интервалът или числото са въведени от потребителя, тогава трябва да се покаже съобщение в друго textField_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 на метода за замяна.

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(...) за разполагане на компоненти, тъй като това прави много негъвкави GUI, които макар да изглеждат добре на една платформа, изглеждат ужасно на повечето други платформи или разделителни способности на екрана и са много трудни за актуализиране и поддръжка.


Редактирайте като използвате предложението на MadProgrammer, помислете дали да позволите на GUI да добави 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
Нуждая се от малко повече помощ от вас. Както в тази програма, когато ще напиша числова стойност или интервал, тя показва НЕПОЗВОЛЕНО (но е постоянно), ако искам да го направя като След натискане на цифра/интервал, трябва да показва НЕПОЗВОЛЕНО, но след това, ако натисна произволен знак тогава NOT ALLOWED трябва да се премахне. Как да го направим ? Бихте ли могли да направите редакции за него в кода по-горе? Благодаря ти @HovercraftFullOfEels - person AshwinK; 15.03.2015
comment
добре Благодаря ви още веднъж. Всъщност не знам много за PropertyChangeListener. Но ще премине през java.docs, ако възникне проблем с разбирането, ще публикува коментар. - person AshwinK; 15.03.2015
comment
@user1995161: Също така, моля, разгледайте и гласувайте за алтернативния код на слушателя на MadProgrammer. Той знае повече за Swing, отколкото вие или аз вероятно някога ще научим. - person Hovercraft Full Of Eels; 15.03.2015
comment
@HovercrafftFullOfEels да, разбира се. - 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 & property listener? Благодаря ви много за отговора и страхотния отговор на моя въпрос. Мисля, че ще отнеме повече от 2-3 часа, за да разберем нещата, публикувани от вас и @Hovercraft. - person AshwinK; 15.03.2015