如何使用 DocumentFIlter 从另一个 class 为 JTextField 设置文本?

How to set text for JTextField from another class using DocumentFIlter?

在下面的示例中,我创建了两个 texField。如果用户输入 space 或数字,则在第一个文本上书写时,它应该在另一个 textField_1 上显示消息。但是一旦用户输入 number/space 它就会给出 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;
}}

这是第二个 class MyDocumentFilter,其中 java.lang.NullPointerException 错误发生在 replace 方法的 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);
 }}

您的 DocumentFilter 需要对显示的 NewDemo GUI 对象的引用。不要像其他人建议的那样只创建一个 new NewDemo 实例,因为这将创建一个不显示的单独实例,而是传入适当的显示引用。

例如,

  ((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 非常不灵活,虽然它们在一个平台上看起来不错,但在大多数其他平台或屏幕分辨率上看起来很糟糕,而且很难实现更新维护。


Edit 使用 MadProgrammer 的建议,考虑允许您的 GUI 将 PropertyChangeListener 添加到 DocumentFilter。这样,任何 class 都可以监听 DocumentFilter 的 "state" 中的变化。在这里,我创建了一个名为 "valid" 的布尔状态,它会在布尔变量发生变化时通知侦听器。

例如:

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);
   }
}

DocumentFilter 不负责修改 UI 的状态。相反,它应该提供状态出错的通知(或者你想知道的任何其他信息)并让委托人决定应该做什么。

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);
        }
    }));

举个例子。