DocumentFilter

Boa tarde a todos.

Criei um DocumentFilter para que meu JTextField aceite somente números, porém quando tento limpar o campo (jTextCodigo.setText("")), ele não aceita, creio que pelo fato de só permitir números. Alguém tem uma dica pra eu solucionar este problema??? Tentei criar um new no Campo e setar novamente o documento para quando eu quiser limpar o texto, porém, algumas implementações que fiz (como por exemplo, quando o usuário pressionar “Enter” com o JTextField com o foco, um getText(), etc).

Desde já agradeço a todos.

Gláuber

Eu não uso DocumentFilter para esse tipo de tarefa, prefiro usar Document. Seguem as classes que uso:

import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

// PlainDocument com limitação ao número máximo de caracteres armazenados.
// Valores de limite menores ou iguais a zero indicam que não haverá
// limitações ao número de caracteres.

public class FixedSizePlainDocument extends PlainDocument {
  // Atributos exportados
  private int maximumSize = 0;

  // Construtor
  public FixedSizePlainDocument(int maximumSize) {
    this.maximumSize = maximumSize;
  }

  public FixedSizePlainDocument() {
    this(0);
  }

  // getXXXX() / setXXXX()
  public int getMaximumSize() {
    return maximumSize;
  }

  public void setMaximumSize(int maximumSize) {
    this.maximumSize = maximumSize;
  }

  // Redefinição do método herdado
  @Override
  public void insertString(int offset, String str, AttributeSet attr)
      throws BadLocationException {
    // Evita strings nulas ou vazias
    if ((str == null) ||
        (str.length() < 1)) {
      return;
    }

    // Só faz checagem de tamanho se o limite for maior do que zero
    if (maximumSize > 0) {
      // Se o texto atual já chegou ao limite, sai
      int curSize = this.getLength();

      if (curSize >= maximumSize) {
        return;
      }

      // Se a soma do comprimento atual do texto com o comprimento do
      // trecho a ser inserido superar o limite ajustado, trunca o
      // trecho a inserir para respeitar o limite
      int strSize = str.length();
      int sumSize = curSize + strSize;

      if (sumSize > maximumSize) {
        int lastPosition = Math.min(strSize, strSize - (sumSize - maximumSize));

        if (lastPosition >= 0) {
          str = str.substring(0, lastPosition);
        }
      }
    }

    // Insere a string
    super.insertString(offset, str, attr);
  }

  // Redefinição do método herdado
  @Override
  public void replace(int offset, int length, String str, AttributeSet attr)
      throws BadLocationException {
    // Só faz checagem de tamanho se o limite for maior do que zero
    if (maximumSize > 0) {
      // Se a soma do comprimento atual do texto, menos o comprimento do trecho
      // que será removido, mais o comprimento do trecho a ser inserido superar
      // o limite ajustado, trunca o trecho inserido para respeitar o limite
      int curSize = this.getLength();
      int strSize = (str != null) ? str.length() : 0;
      int sumSize = curSize - length + strSize;

      if (sumSize > maximumSize) {
        int lastPosition = Math.min(strSize, strSize - (sumSize - maximumSize));

        if ((lastPosition >= 0) &&
            (str != null)) {
          str = str.substring(0, lastPosition);
        }
      }
    }

    // Substitui a string
    super.replace(offset, length, str, attr);
  }
}
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;

// PlainDocument especializado para edição de números inteiros.

public class IntegerNumberPlainDocument extends FixedSizePlainDocument {
  // Construtor
  public IntegerNumberPlainDocument(int maximumSize) {
    super(maximumSize);
  }

  public IntegerNumberPlainDocument() {
    this(0);
  }

  // Redefinição do método herdado
  @Override
  public void insertString(int offset, String str, AttributeSet attr)
      throws BadLocationException {
    // Evita strings nulas ou vazias
    if ((str == null) ||
        (str.length() < 1)) {
      return;
    }

    // Checa o primeiro caractere para saber se a string digitada
    // é numérica ou alfabética. Normalmente isso é suficiente para
    // nossas checagens, pois o mais comum é que esta rotina só receba
    // um caractere por chamada. Porém, se <str> tiver comprimento
    // maior do que 1 (por exemplo, ao colar texto com Ctrl+V), a
    // seqüência gerada pela concatenação da string atual do documento
    // com a nova string pode gerar um valor inválido. Dessa forma, é
    // imprescindível validar posteriormente a string resultante quando
    // chegar a hora de convertê-la para número
    char c = str.charAt(0);

    switch (c) {
      // Caracteres numéricos
      case '0': case '1': case '2':
      case '3': case '4': case '5':
      case '6': case '7': case '8':
      case '9':
        // ... Nada a fazer ...
        break;

      case '-': {  // Sinal de menos (-)
          int curSize = this.getLength();

          if (curSize > 0) {
            // Se a string atual no documento já contiver um sinal de
            // menos, sai da rotina
            String txt = this.getText(0, curSize);

            if (txt.indexOf(String.valueOf(c)) != -1) {
              return;
            }
          }
        }

        break;

      default:  // Demais caracteres
        // Sai da rotina
        return;
    }

    // Insere a string
    super.insertString(offset, str, attr);
  }

  // Redefinição do método herdado
  @Override
  public void replace(int offset, int length, String str, AttributeSet attr)
      throws BadLocationException {
    if ((str != null) &&
        (str.length() > 0)) {
      // Checa o primeiro caractere para saber se a string digitada
      // é numérica ou alfabética. Normalmente isso é suficiente para
      // nossas checagens, pois o mais comum é que esta rotina só receba
      // um caractere por chamada. Porém, se <str> tiver comprimento
      // maior do que 1 (por exemplo, ao colar texto com Ctrl+V), a
      // seqüência gerada pela concatenação da string atual do documento
      // com a nova string pode gerar um valor inválido. Dessa forma, é
      // imprescindível validar posteriormente a string resultante quando
      // chegar a hora de convertê-la para número
      char c = str.charAt(0);

      switch (c) {
        // Caracteres numéricos
        case '0': case '1': case '2':
        case '3': case '4': case '5':
        case '6': case '7': case '8':
        case '9':
          // ... Nada a fazer ...
          break;

        case '-': {  // Sinal de menos (-)
            int curSize = this.getLength();

            if (curSize > 0) {
              // Se a string atual no documento já contiver um sinal de
              // menos, sai da rotina
              String txt = this.getText(0, curSize);

              if (txt.indexOf(String.valueOf(c)) != -1) {
                return;
              }
            }
          }

          break;

        default:  // Demais caracteres
          // Sai da rotina
          return;
      }
    }

    super.replace(offset, length, str, attr);
  }
}

Obrigado Roger.

Vou tentar implementar e depois posto o Resultado.
Mais alguém se habilita a tentar resolver este problema utilizando DocumentFilter?? Sou novato em Java (swing nem se fala) e toda ajuda será bem vinda.

Um abraço,
Gláuber

Boa tarde a todos. Após uma boa procura, achei uma solução para meu DocumentFilter: fiz a implementação do método remove.

public void remove(DocumentFilter.FilterBypass fb, int offset, int length) throws BadLocationException{
Document doc = fb.getDocument();
int currentLength = doc.getLength();
String currentContent = doc.getText(0, currentLength);
String before = currentContent.substring(0, offset);
String after = currentContent.substring(length + offset, currentLength);
String newValue = before + after;
fb.remove(offset, length);
}

e na minha aplicação, quando quero limpar o documento, utilizo:

jTextCodigo.getDocument().remove(0, jTextCodigo.getText().length());

Espero que sirva pra mais alguém.

Um abraço,
Gláuber