JTextField для автоматического удаления символов при перезаписи - PullRequest
0 голосов
/ 26 марта 2019

Я работаю с Java, и у меня есть JTextField, который может иметь только 4 цифры.Я использую класс, который расширяет DocumentFilter, чтобы отфильтровать любой другой символ и ограничить количество символов до 4.

Проблема в том, что если у меня есть 4 цифры, если я выберу все из них и попробуючтобы перезаписать их, набрав другую цифру, она не перезаписывается автоматически и ничего не делает, мне нужно явно набрать «Backspace» или «Delete» на моей клавиатуре, чтобы удалить 4 цифры, а затем (после того, как полеочистить) Я могу снова напечатать.

Как я могу заставить JTextField действовать как остальная часть операционной системы, что после того, как у меня выделен какой-то текст, если я набираю символ, он «удаляет все, затем записывает символ» (он подставляет содержимое).

У меня есть один вспомогательный класс, JustLimitDigitFilter.java:

import javax.swing.text.DocumentFilter;
import javax.swing.text.BadLocationException;

import java.awt.Toolkit;

import javax.swing.text.AttributeSet;

public class JustLimitDigitFilter extends DocumentFilter {

  int limit;

  public JustLimitDigitFilter(int limit) {
    this.limit = limit;
  }

  @Override
  public void insertString(DocumentFilter.FilterBypass fb, int offset, String text, AttributeSet attr) throws BadLocationException {

    // if (text == null) {
    //   return;
    // }
    String str = text.replaceAll("\\D", "");
    if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit) {
      super.insertString(fb, offset, str, attr);
    } else {
      Toolkit.getDefaultToolkit().beep();
    }

  }

  @Override
  public void replace(DocumentFilter.FilterBypass fb, int offset, int length, String text, AttributeSet attr)
      throws BadLocationException {

    // if (text == null) {
    //   return;
    // }
    String str = text.replaceAll("\\D", "");
    if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit) {
      super.replace(fb, offset, length, str, attr);
    } else {
      Toolkit.getDefaultToolkit().beep();
    }

  }

}

И основной класс, App.java:

import java.awt.EventQueue;

import javax.swing.JFrame;
import javax.swing.JPanel;
import java.awt.BorderLayout;
import javax.swing.JTextField;
import javax.swing.text.AbstractDocument;
import javax.swing.text.DocumentFilter;

public class App {

  private JFrame frame;
  private JTextField textField;

  /**
   * Launch the application.
   */
  public static void main(String[] args) {
    EventQueue.invokeLater(new Runnable() {
      public void run() {
        try {
          App window = new App();
          window.frame.setVisible(true);
        } catch (Exception e) {
          e.printStackTrace();
        }
      }
    });
  }

  /**
   * Create the application.
   */
  public App() {
    initialize();
  }

  /**
   * Initialize the contents of the frame.
   */
  private void initialize() {
    frame = new JFrame();
    frame.setBounds(100, 100, 191, 96);
    frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
    frame.getContentPane().setLayout(null);

    JPanel panel = new JPanel();
    panel.setBounds(6, 6, 179, 62);
    frame.getContentPane().add(panel);
    panel.setLayout(null);

    textField = new JTextField();
    textField.setBounds(6, 6, 167, 26);
    panel.add(textField);
    textField.setColumns(10);

    // without this code below this, the textfield is “normal” when
    // something is selected if I write it overwrites the selection

    AbstractDocument doc = (AbstractDocument) textField.getDocument();
    doc.setDocumentFilter(new JustLimitDigitFilter(4));
  }

}

Любые предложения приветствуются, поскольку я новичок в этом, за исключением тех сомнений, которые у меня есть.

Ответы [ 2 ]

2 голосов
/ 26 марта 2019

Метод replace() в классе DocumentFilter фактически выполняет две операции. Сначала он удаляет length символов, начиная с offset, после чего он вставляет text в offset. Следовательно, следующая строка в вашем методе replace() не вызывает ничего, когда JTextField содержит максимально допустимое количество символов ...

if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit) {

Если JTextField заполнен, то его длина будет максимальным количеством символов, поэтому при добавлении длины str всегда будет больше limit.

1 голос
/ 26 марта 2019

Расширение ответа Абры:

Параметр "length" в методе replace(...) содержит количество символов, которые будут удалены.

Таким образом, вы можете изменить свой оператор if на:

//if (!str.isEmpty() && (fb.getDocument().getLength() + str.length()) <= limit)
if (!str.isEmpty() && (fb.getDocument().getLength() + str.length() - length) <= limit)

После этого изменения вы можете упростить метод insert(...) до:

@Override
public void insertString(FilterBypass fb, int offset, String text, AttributeSet attributes)
    throws BadLocationException
{
    replace(fb, offset, 0, text, attributes);
}
...