Campo numérico, Dinheiro, Money, etc... [O RETORNO 2!]

Oi pessoal,
com base no sucesso do meu outro tópico (JMoneyField) decidi
colocar um novo campo que pode ser usado como monetario…
esse código é mais maduro e muito mais personalizavel :stuck_out_tongue:
aproveitem, comentem, e melhorem!!!

// Pacote aoqual a classe pertence
package neocode.lib.graphic.field;

// Importa as bibilotecas Java necessárias
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 * Campo para a inserção de números com base em um formato.
 * 
 * @author Dyorgio da Silva Nascimento
 */
public class JNumberFormatField extends JTextField {

  private static final long serialVersionUID = -7506506392528621022L;

  private static final NumberFormat MONETARY_FORMAT = new DecimalFormat("#,##0.00");

  private NumberFormat numberFormat;

  private int limit = -1;

  public JNumberFormatField(int casasDecimais) {
    this(new DecimalFormat((casasDecimais == 0 ? "#,##0" : "#,##0.") + makeZeros(casasDecimais)));
  }

  public JNumberFormatField() {
    this(MONETARY_FORMAT);
  }

  public JNumberFormatField(NumberFormat format) {
    // define o formato do número
    numberFormat = format;
    // alinhamento horizontal para o texto
    setHorizontalAlignment(RIGHT);
    // documento responsável pela formatação do campo
    setDocument(new PlainDocument() {

      private static final long serialVersionUID = 1L;

      @Override
      public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
        String text = new StringBuilder(JNumberFormatField.this.getText().replaceAll("[^0-9]", "")).append(
            str.replaceAll("[^0-9]", "")).toString();
        super.remove(0, getLength());
        if (text.isEmpty()) {
          text = "0";
        }else{
          text = new BigInteger(text).toString();
        }

        super.insertString(0, numberFormat.format(new BigDecimal(getLimit() > 0 && text.length() > getLimit() ? text
            .substring(0, getLimit()) : text).divide(new BigDecimal(Math.pow(10, numberFormat
            .getMaximumFractionDigits())))), a);
      }

      @Override
      public void remove(int offs, int len) throws BadLocationException {
        super.remove(offs, len);
        if (len != getLength()) {
          insertString(0, "", null);
        }
      }
    });
    // mantem o cursor no final do campo
    addCaretListener(new CaretListener() {

      boolean update = false;

      @Override
      public void caretUpdate(CaretEvent e) {
        if (!update) {
          update = true;
          setCaretPosition(getText().length());
          update = false;
        }
      }
    });
    // limpa o campo se apertar DELETE
    addKeyListener(new KeyAdapter() {

      @Override
      public void keyPressed(KeyEvent e) {
        if (e.getKeyCode() == KeyEvent.VK_DELETE) {
          setText("");
        }
      }
    });
    // formato inicial
    setText("0");
    setCaretPosition(getText().length());
  }

  /**
   * Define um valor BigDecimal ao campo
   * 
   * @param value
   */
  public void setValue(BigDecimal value) {
    super.setText(numberFormat.format(value));
  }

  /**
   * Recupera um valor BigDecimal do campo
   * 
   * @return
   */
  public final BigDecimal getValue() {
    return new BigDecimal(getText().replaceAll("[^0-9]", "")).divide(new BigDecimal(Math.pow(10, numberFormat
        .getMaximumFractionDigits())));
  }

  /**
   * Recupera o formatador atual do campo
   * 
   * @return
   */
  public NumberFormat getNumberFormat() {
    return numberFormat;
  }

  /**
   * Define o formatador do campo
   * 
   * @param numberFormat
   */
  public void setNumberFormat(NumberFormat numberFormat) {
    this.numberFormat = numberFormat;
  }

  /**
   * Preenche um StringBuilder com zeros
   * 
   * @param zeros
   * @return
   */
  private static final String makeZeros(int zeros) {
    if (zeros >= 0) {
      StringBuilder builder = new StringBuilder();

      for (int i = 0; i < zeros; i++) {
        builder.append('0');
      }
      return builder.toString();
    } else {
      throw new RuntimeException("Número de casas decimais inválida (" + zeros + ")");
    }
  }

  /**
   * Recupera o limite do campo.
   * 
   * @return
   */
  public int getLimit() {
    return limit;
  }

  /**
   * Define o limite do campo, limit < 0 para deixar livre (default) Ignora os pontos e virgulas do formato, conta
   * somente com os números
   * 
   * @param limit
   */
  public void setLimit(int limit) {
    this.limit = limit;
  }

  // testes, pode ser removido
  public static void main(String[] args) {
    JFrame frame = new JFrame("Teste do campo");
    frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
    frame.setResizable(false);
    frame.add(new JNumberFormatField(new DecimalFormat("0.000")) {

      {
        // limita a 4 caracteres
        setLimit(4);
      }
    });
    frame.pack();
    frame.setLocationRelativeTo(null);
    frame.setVisible(true);
  }
}

Legal, ficou otimo

Eu não consegui executar o comando getValue()

Quando eu jogo ele no netbeans e tento usar este metodo ao inves do getText ele reclama que não existe

Tem como limitar o tamanho do campo também? tipo quero um campo para CFOP 5.102, teria que ter 3 decimais e caber apenas um inteiro

Dario

O problema é do NetBeans…
remove o componente da paleta, fecha, abre e adiciona denovo
Quanto ao seu problema mudei um pouco o código
para suportar limitações no campo.

Abs,

Quanto ao netbeans ta tranquilo, nem joguei pra paleta

Eu to criando direto como custom code mas eu acho que to fazendo errado na hora de querer pegar o valor

To fazendo

valor.getValue() ele diz que não existe este metodo

Criei o objeto no custom code do TextField assim

new JNumberFormatField(new DecimalFormat("0.00")) {
      {
        setLimit(6);
      }
    }

Dario

Esse é o seu problema então,
o NetBeans declarou o TextField como
JtextField…
não importa que vc fez um custom com JNumberFormatField,
pro Java o que interessa é o tipo na declaração, e não na instancialização (new).
Adicione o JNumberformatField na paleta ou mude o tipo da variavel
para JNumberformatField, ou em ultimo caso faça um cast

// desse jeito o java enchergará
((JNumberFormatField)seuCampoDeTexto).getValue();

e vê se estuda mais o Java, que tal o eclipse?
o NetBeans ta te deixando “por fora” da linguagem creio eu…

Abs,

Entendi,

Quero tentar alterar o codigo para que ele se inicialize assim:

new JNumberFormatField(14,2)

onde 14 eh a quantidade de caracteres que ele pode aceitar incluindo o ponto

e 2 eh o numero de decimais que ele vai ter ja incluso no numero 14

por exemplo (6,2) seria 999.99

Obrigado

Dario

Dyorgio

Parabens,

Consegui implementar o código para meu proposito, alterei apenas as linhas do código abaixo:

  public JNumberFormatField(int casasTotal, int casasDecimais) {
      this(new DecimalFormat((casasDecimais == 0 ? "#,##0" : "#,##0.") + makeZeros(casasDecimais)));
      this.setLimit(casasTotal-1);
  }

  public JNumberFormatField(int casasTotal) {
      this(new DecimalFormat((0 == 0 ? "#,##0" : "#,##0.") + makeZeros(0)));
      this.setLimit(casasTotal);
  }
  
  public JNumberFormatField() {
      this(new DecimalFormat((2 == 0 ? "#,##0" : "#,##0.") + makeZeros(2)));
      this.setLimit(14-1);
  }

Agora posso iniciar com:

new JNumberFormatField() -> ele pega um padrão default

new JNumberFormatField(11) -> ele pega um inteiro com 11 posições

new JNumberFormatField(6,2) -> ele pega um campo fracionario com 6 posições incluindo a virgula e com duas decimais

Obrigadão,

Dario

ps. você já fez um código deste tipo para formatar DATAS onde ele permita que se digite 13/10/77 e ele já complemente ao sair do campo para 13/10/1977 e ainda não deixe sair do campo se a data for invalida?

Dario.

Ola vc tem ai um codigo para resolver este problema:

Como fazer auto-incremento no PostGreSql usando String no campo codigo e preencher com zeros a esquerda

Colocar zeros a esquerda eh simples,

    public String strZero( int value, int n ){
        String s = Integer.toString( value ).trim();
        StringBuffer resp = new StringBuffer();
        int fim = n - s.length();
        for( int x = 0; x < fim; x++ )
          resp.append( '0' );
        return resp + s;
    }    

Quanto ao autoincrement o proprio postgreSQL faz isto, é só você criar uma tabela com um campo AUTOINCREMENT

Dario

vc criou uma string e como aplicar nos campos?

Outra coisa é como usar um codigo de um tabela para formar o codigo de outra.

ex.

cad-bairro… tem o campo codigo da cidade, o codigo da cidade for 0000002
o codigo do primeiro bairro sera gerado no momento que eu clicar em gravar como 0000021.

pode me ajudar com isso tambem.

obrigado

Dario, esse seu auto complete é meio arriscado,
no exemplo qeu vc colocou esta certo, pois 77 na nossa época esta mais para a década de 90,
mais se o cara digitar 55?
o correto seria colocar para 2055…já que esta mais para o século 21,
ai o cara preenche a data de nascimento dele e vai pro século 21 haehahehaheahe
o ideal, e que é o mais encontrado por ai, é a digitação da data completa,
ou algo com combos…
Pessoalmente eu prefiro combos, assim vc nem precisa se preocupar com datas inválidas,
da pra colocar o mês em string tb :P, Janeiro, fevereiro
ainda da pra fazer com JSpinner tb…

Abs,

[quote=dyorgio]Oi pessoal,
com base no sucesso do meu outro tópico (JMoneyField) decidi
colocar um novo campo que pode ser usado como monetario…
esse código é mais maduro e muito mais personalizavel :stuck_out_tongue:
aproveitem, comentem, e melhorem!!!

[code]
// Pacote aoqual a classe pertence
package neocode.lib.graphic.field;

// Importa as bibilotecas Java necessárias
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**

  • Campo para a inserção de números com base em um formato.
  • @author Dyorgio da Silva Nascimento
    */
    public class JNumberFormatField extends JTextField {

private static final long serialVersionUID = -7506506392528621022L;

private static final NumberFormat MONETARY_FORMAT = new DecimalFormat("#,##0.00");

private NumberFormat numberFormat;

private int limit = -1;

public JNumberFormatField(int casasDecimais) {
this(new DecimalFormat((casasDecimais == 0 ? "#,##0" : "#,##0.") + makeZeros(casasDecimais)));
}

public JNumberFormatField() {
this(MONETARY_FORMAT);
}

public JNumberFormatField(NumberFormat format) {
// define o formato do número
numberFormat = format;
// alinhamento horizontal para o texto
setHorizontalAlignment(RIGHT);
// documento responsável pela formatação do campo
setDocument(new PlainDocument() {

  private static final long serialVersionUID = 1L;

  @Override
  public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
    String text = new StringBuilder(JNumberFormatField.this.getText().replaceAll(&quot;[^0-9]&quot;, &quot;&quot;)).append(
        str.replaceAll(&quot;[^0-9]&quot;, &quot;&quot;)).toString();
    super.remove(0, getLength());
    if (text.isEmpty()) {
      text = &quot;0&quot;;
    }else{
      text = new BigInteger(text).toString();
    }

    super.insertString(0, numberFormat.format(new BigDecimal(getLimit() &gt; 0 && text.length() &gt; getLimit() ? text
        .substring(0, getLimit()) : text).divide(new BigDecimal(Math.pow(10, numberFormat
        .getMaximumFractionDigits())))), a);
  }

  @Override
  public void remove(int offs, int len) throws BadLocationException {
    super.remove(offs, len);
    if (len != getLength()) {
      insertString(0, &quot;&quot;, null);
    }
  }
});
// mantem o cursor no final do campo
addCaretListener(new CaretListener() {

  boolean update = false;

  @Override
  public void caretUpdate(CaretEvent e) {
    if (!update) {
      update = true;
      setCaretPosition(getText().length());
      update = false;
    }
  }
});
// limpa o campo se apertar DELETE
addKeyListener(new KeyAdapter() {

  @Override
  public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_DELETE) {
      setText(&quot;&quot;);
    }
  }
});
// formato inicial
setText(&quot;0&quot;);
setCaretPosition(getText().length());

}

/**

  • Define um valor BigDecimal ao campo
  • @param value
    */
    public void setValue(BigDecimal value) {
    super.setText(numberFormat.format(value));
    }

/**

  • Recupera um valor BigDecimal do campo
  • @return
    */
    public final BigDecimal getValue() {
    return new BigDecimal(getText().replaceAll("[^0-9]", "")).divide(new BigDecimal(Math.pow(10, numberFormat
    .getMaximumFractionDigits())));
    }

/**

  • Recupera o formatador atual do campo
  • @return
    */
    public NumberFormat getNumberFormat() {
    return numberFormat;
    }

/**

  • Define o formatador do campo
  • @param numberFormat
    */
    public void setNumberFormat(NumberFormat numberFormat) {
    this.numberFormat = numberFormat;
    }

/**

  • Preenche um StringBuilder com zeros

  • @param zeros

  • @return
    */
    private static final String makeZeros(int zeros) {
    if (zeros >= 0) {
    StringBuilder builder = new StringBuilder();

    for (int i = 0; i < zeros; i++) {
    builder.append(‘0’);
    }
    return builder.toString();
    } else {
    throw new RuntimeException(“Número de casas decimais inválida (” + zeros + “)”);
    }
    }

/**

  • Recupera o limite do campo.
  • @return
    */
    public int getLimit() {
    return limit;
    }

/**

  • Define o limite do campo, limit < 0 para deixar livre (default) Ignora os pontos e virgulas do formato, conta
  • somente com os números
  • @param limit
    */
    public void setLimit(int limit) {
    this.limit = limit;
    }

// testes, pode ser removido
public static void main(String[] args) {
JFrame frame = new JFrame("Teste do campo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(false);
frame.add(new JNumberFormatField(new DecimalFormat("0.000")) {

  {
    // limita a 4 caracteres
    setLimit(4);
  }
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

}
}
[/code][/quote]
Boa noite Caro amigo, estou precisando de uma focinha estive olhando essa class sua e achei muito interessante então pensei em usar, mais ai é q ta o problema não estou sabendo usa a sua class será q vc pode me da uma ajuda.

no momento estou usando essa daqui ate q esta atendendo a minha necessidade, mas tem um problema não consigo seta o valor q vem do banco para o campo q recebe essa implementação e infelizmente não sei implementa essa funcionalidade nesse código.

/*
 * To change this template, choose Tools | Templates
 * and open the template in the editor.
 */
package Util;

import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 *
 * @author kelow
 */
public class MonetarioDocument extends PlainDocument {

    private static final NumberFormat MONETARY_FORMAT = new DecimalFormat("R$ #,##0.00");
    public static final int NUMERO_DIGITOS_MAXIMO = 12;

    @Override
    public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {

        String texto = getText(0, getLength());
        for (int i = 0; i < str.length(); i++) {
            char c = str.charAt(i);
            if (!Character.isDigit(c)) {
                return;
            }
        }


        if (texto.length() < MonetarioDocument.NUMERO_DIGITOS_MAXIMO) {
            super.remove(0, getLength());
            texto = texto.replace(".", "").replace(",", "");
            StringBuilder s = new StringBuilder(texto + str);
            
            if (s.length() > 0 && s.charAt(0) == '0') {
                s.deleteCharAt(0);
            }

            if (s.length() < 3) {
                if (s.length() < 1) {
                    s.insert(0, "000");
                } else if (s.length() < 2) {
                    s.insert(0, "00");
                } else {
                    s.insert(0, "0");
                }
            }

            s.insert(s.length() - 2, ",");

            if (s.length() > 6) {
                s.insert(s.length() - 6, ".");
            }

            if (s.length() > 10) {
                s.insert(s.length() - 10, ".");
            }

            super.insertString(0, s.toString(), a);
        }
    }

    @Override
    public void remove(int offset, int length) throws BadLocationException {
        super.remove(offset, length);
        String texto = getText(0, getLength());
        texto = texto.replace(",", "");
        texto = texto.replace(".", "");
        super.remove(0, getLength());
        insertString(0, texto, null);
    }
    
    

}

então para o momento só queria q ele fizer o retorno do banco de dado para o campo. Deste já agradeço a colaboração dos colegas do guj. Um forte abraço a tds.

Opa,

Cara, verifica se quando você esta setando o valor que vem do banco, o mesmo não esta com algum ponto ou virgula,
pois o seguin te trecho do código invalida esse tipo de input:

if (!Character.isDigit(c)) {  
                return;  
            }  

Bom dia dyorgio, realmente ele vem como Double do banco e percebi q ele invalida agora como eu devo fazer para consegui representa esse valor no JFormattedTextField.

Você tem trescaminhos,

  1. Antes de setar o valor no campo, converte para string porem multiplica antes para não perder casas decimais, por exemplo 1.23 = String.valueOf((int)(1.23*100)) = “123”

  2. Ajustar seu codigo para aceitar os pontos…porem você esta no lugar errado caso esteja buscando ajuste no seu código, aqui é um tópico sobre o codigo postado acima.

  3. Usar o código que esta nesse topico, o mesmo já trabalha com BigDecimal (que possui construtor que aceita double).

Galera eu to fazendo um função usando essa classe só que ai acontece o seguinte
A função ta lisa eu vou postar a linha mais ou menos como eu fiz.

public void PegaValor (JNumberFormatField valor) { int numero = Integer.valueOf(valor.getValue().toString()); }
na hora de declarar ficaria assim

só que na hora que eu declaro a função da erro como se eu tivesse pondo um outro objeto la alguem me ajuda por favor

Boa tarde. Mais de uma ano e esse tópico ainda é muito útil.
Minha duvida é, como alterar este código para que no lugar da vírgula como separador decimal eu coloque um ponto?
Tentei simplesmente alterar o código colocando ponto no lugar de virgula e/ou virgula no lugar de ponto, mas nada da certo.
Preciso do ponto como separador decimal, pois o valor digitado irá para o banco de dados que só aceita ponto e não vírgula.

[quote=dyorgio]Oi pessoal,
com base no sucesso do meu outro tópico (JMoneyField) decidi
colocar um novo campo que pode ser usado como monetario…
esse código é mais maduro e muito mais personalizavel :stuck_out_tongue:
aproveitem, comentem, e melhorem!!!

[code]
// Pacote aoqual a classe pertence
package neocode.lib.graphic.field;

// Importa as bibilotecas Java necessárias
import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;

import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**

  • Campo para a inserção de números com base em um formato.
  • @author Dyorgio da Silva Nascimento
    */
    public class JNumberFormatField extends JTextField {

private static final long serialVersionUID = -7506506392528621022L;

private static final NumberFormat MONETARY_FORMAT = new DecimalFormat("#,##0.00");

private NumberFormat numberFormat;

private int limit = -1;

public JNumberFormatField(int casasDecimais) {
this(new DecimalFormat((casasDecimais == 0 ? "#,##0" : "#,##0.") + makeZeros(casasDecimais)));
}

public JNumberFormatField() {
this(MONETARY_FORMAT);
}

public JNumberFormatField(NumberFormat format) {
// define o formato do número
numberFormat = format;
// alinhamento horizontal para o texto
setHorizontalAlignment(RIGHT);
// documento responsável pela formatação do campo
setDocument(new PlainDocument() {

  private static final long serialVersionUID = 1L;

  @Override
  public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
    String text = new StringBuilder(JNumberFormatField.this.getText().replaceAll(&quot;[^0-9]&quot;, &quot;&quot;)).append(
        str.replaceAll(&quot;[^0-9]&quot;, &quot;&quot;)).toString();
    super.remove(0, getLength());
    if (text.isEmpty()) {
      text = &quot;0&quot;;
    }else{
      text = new BigInteger(text).toString();
    }

    super.insertString(0, numberFormat.format(new BigDecimal(getLimit() &gt; 0 && text.length() &gt; getLimit() ? text
        .substring(0, getLimit()) : text).divide(new BigDecimal(Math.pow(10, numberFormat
        .getMaximumFractionDigits())))), a);
  }

  @Override
  public void remove(int offs, int len) throws BadLocationException {
    super.remove(offs, len);
    if (len != getLength()) {
      insertString(0, &quot;&quot;, null);
    }
  }
});
// mantem o cursor no final do campo
addCaretListener(new CaretListener() {

  boolean update = false;

  @Override
  public void caretUpdate(CaretEvent e) {
    if (!update) {
      update = true;
      setCaretPosition(getText().length());
      update = false;
    }
  }
});
// limpa o campo se apertar DELETE
addKeyListener(new KeyAdapter() {

  @Override
  public void keyPressed(KeyEvent e) {
    if (e.getKeyCode() == KeyEvent.VK_DELETE) {
      setText(&quot;&quot;);
    }
  }
});
// formato inicial
setText(&quot;0&quot;);
setCaretPosition(getText().length());

}

/**

  • Define um valor BigDecimal ao campo
  • @param value
    */
    public void setValue(BigDecimal value) {
    super.setText(numberFormat.format(value));
    }

/**

  • Recupera um valor BigDecimal do campo
  • @return
    */
    public final BigDecimal getValue() {
    return new BigDecimal(getText().replaceAll("[^0-9]", "")).divide(new BigDecimal(Math.pow(10, numberFormat
    .getMaximumFractionDigits())));
    }

/**

  • Recupera o formatador atual do campo
  • @return
    */
    public NumberFormat getNumberFormat() {
    return numberFormat;
    }

/**

  • Define o formatador do campo
  • @param numberFormat
    */
    public void setNumberFormat(NumberFormat numberFormat) {
    this.numberFormat = numberFormat;
    }

/**

  • Preenche um StringBuilder com zeros

  • @param zeros

  • @return
    */
    private static final String makeZeros(int zeros) {
    if (zeros >= 0) {
    StringBuilder builder = new StringBuilder();

    for (int i = 0; i < zeros; i++) {
    builder.append(‘0’);
    }
    return builder.toString();
    } else {
    throw new RuntimeException(“Número de casas decimais inválida (” + zeros + “)”);
    }
    }

/**

  • Recupera o limite do campo.
  • @return
    */
    public int getLimit() {
    return limit;
    }

/**

  • Define o limite do campo, limit < 0 para deixar livre (default) Ignora os pontos e virgulas do formato, conta
  • somente com os números
  • @param limit
    */
    public void setLimit(int limit) {
    this.limit = limit;
    }

// testes, pode ser removido
public static void main(String[] args) {
JFrame frame = new JFrame("Teste do campo");
frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
frame.setResizable(false);
frame.add(new JNumberFormatField(new DecimalFormat("0.000")) {

  {
    // limita a 4 caracteres
    setLimit(4);
  }
});
frame.pack();
frame.setLocationRelativeTo(null);
frame.setVisible(true);

}
}
[/code][/quote]

Muito bom seu componente, já uso ele há algum tempo, porém estou tendo uma única dificuldade, valor negativos, pelo o que eu testei ele não aceita valores negativos, você tem algum tratamento para esses casos?

Obrigado.

Aceitar números negativos

import java.awt.event.KeyAdapter;
import java.awt.event.KeyEvent;
import java.math.BigDecimal;
import java.math.BigInteger;
import java.text.DecimalFormat;
import java.text.NumberFormat;
import javax.swing.JFrame;
import javax.swing.JTextField;
import javax.swing.event.CaretEvent;
import javax.swing.event.CaretListener;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

/**
 * Campo para a inserção de números com base em um formato.
 *
 * @author Dyorgio da Silva Nascimento
 */
public class JNumberFormatField extends JTextField {

    private static final long serialVersionUID = -7506506392528621022L;
    private static final NumberFormat MONETARY_FORMAT = new DecimalFormat("R$ #,##0.00");
    private NumberFormat numberFormat;
    private int limit = -1;

    public JNumberFormatField(int casasDecimais) {
        this(new DecimalFormat((casasDecimais == 0 ? "#,##0" : "#,##0.") + makeZeros(casasDecimais)));
    }

    public JNumberFormatField() {
        this(MONETARY_FORMAT);
    }

    public JNumberFormatField(NumberFormat format) {// define o formato do
        // número
        numberFormat = format;// alinhamento horizontal para o texto
        setHorizontalAlignment(RIGHT);// documento responsável pela formatação
        // do campo
        setDocument(new PlainDocument() {
            private static final long serialVersionUID = 1L;

            @Override
            public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
                String first = (!JNumberFormatField.this.getText().isEmpty()) ? String.valueOf(JNumberFormatField.this.getText().charAt(0)) : "";
                String fStr = (!str.isEmpty()) ? String.valueOf(str.charAt(0)) : "";
                String text = new StringBuilder(JNumberFormatField.this.getText().replaceAll("[^0-9]", "")).append(str.replaceAll("[^0-9]", "")).toString();

                super.remove(0, getLength());
                if (text.isEmpty()) {
                    text = "0";
                } else {
                    text = new BigInteger(text).toString();
                }

                BigDecimal n = new BigDecimal(getLimit() > 0 == text.length() > getLimit() ? text.substring(0, getLimit()) : text).divide(new BigDecimal(Math.pow(10, numberFormat.getMaximumFractionDigits())));

                if (str.equals("-") || first.equals("-") || fStr.equals("-")) {
                    n = n.multiply(new BigDecimal(-1));
                }

                super.insertString(0, numberFormat.format(n), a);
            }

            @Override
            public void remove(int offs, int len) throws BadLocationException {
                super.remove(offs, len);
                if (len != getLength()) {
                    insertString(0, "", null);
                }
            }
        });// mantem o cursor no final
        // do campo
        addCaretListener(new CaretListener() {
            boolean update = false;

            @Override
            public void caretUpdate(CaretEvent e) {
                if (!update) {
                    update = true;
                    setCaretPosition(getText().length());
                    update = false;
                }
            }
        });// limpa o campo se
        // apertar DELETE
        addKeyListener(new KeyAdapter() {
            @Override
            public void keyPressed(KeyEvent e) {
                if (e.getKeyCode() == KeyEvent.VK_DELETE) {
                    setText("");
                }
            }
        });// formato
        // inicial
        setText("0");
        setCaretPosition(getText().length());
    }

    /**
     * *
     * Define um valor BigDecimal ao campo**
     *
     * @param value
     */
    public void setValue(BigDecimal value) {
        super.setText(numberFormat.format(value));
    }

    /**
     * *
     * Recupera um valor BigDecimal do campo**
     *
     * @return
     */
    public final BigDecimal getValue() {
        String first = (!getText().isEmpty()) ? String.valueOf(getText().charAt(0)) : "0";

        BigDecimal valor = new BigDecimal(getText().replaceAll("[^0-9]", "")).divide(new BigDecimal(Math.pow(10, numberFormat.getMaximumFractionDigits())));
        if (first.equals("-")) {
            valor = valor.multiply(new BigDecimal(-1));
        }
        return valor;
    }

    /**
     * *
     * Recupera o formatador atual do campo**
     *
     * @return
     */
    public NumberFormat getNumberFormat() {
        return numberFormat;
    }

    /**
     * *
     * Define o formatador do campo** @param numberFormat
     */
    public void setNumberFormat(NumberFormat numberFormat) {
        this.numberFormat = numberFormat;
    }

    /**
     * *
     * Preenche um StringBuilder com zeros** @param zeros*
     *
     * @return
     */
    private static final String makeZeros(int zeros) {
        if (zeros >= 0) {
            StringBuilder builder = new StringBuilder();
            for (int i = 0; i < zeros; i++) {
                builder.append('0');
            }
            return builder.toString();
        } else {
            throw new RuntimeException("Número de casas decimais inválida (" + zeros + ")");
        }
    }

    /**
     * *
     * Recupera o limite do campo.** @return
     */
    public int getLimit() {
        return limit;
    }

    /**
     * *
     * Define o limite do campo, limit < 0 para deixar livre (default) Ignora os
     * pontos e virgulas do formato, conta* somente com os números** @param
     * limit
     */
    public void setLimit(int limit) {
        this.limit = limit;
    }

    // testes, pode ser removido
    public static void main(String[] args) {
        JFrame frame = new JFrame("Teste do campo");
        frame.setDefaultCloseOperation(JFrame.DISPOSE_ON_CLOSE);
        frame.setResizable(false);
        frame.add(new JNumberFormatField() {
            {// limita a 4
                // caracteres
                setLimit(4);
            }
        });
        frame.pack();
        frame.setLocationRelativeTo(null);
        frame.setVisible(true);
    }
}