É muito comum encontrar nos fóruns especializados em Java a seguinte questão: "Como eu faço para limitar o tamanho de um JtextField?". Ocorre um certo desapontamento dos iniciantes na linguagem por não haver um método chamado setMaxLenght(x). Ou ainda com os que trabalham visualmente, procurar a propriedade no componente que limitaria o tamanho máximo de caracteres e não encontrar. Aí programadores que vieram do Delphi por exemplo dizem "O Delphi é muito melhor, blablabla...". Só digo uma coisa: Revejam seus conceitos sobre o que é Java.
A verdade é que o componente JTextField é definido sobre um modelo de documento que por padrão é chamado PlainDocument. Portanto, para para ter o controle sobre o JTextField devemos criar uma sub classe de PlainDocument, sobrescrever alguns métodos dela e trocar o modelo do JTextField para este novo.
Minha intenção não é entrar a fundo neste assunto, mas sim dar uma solução principalmente pra quem está trabalhando visualmente e não quer ficar editanto código a todo momento.
Então vamos lá, primeiramente crie a seguinte classe no seu projeto:
import javax.swing.text.AttributeSet; import javax.swing.text.BadLocationException; import javax.swing.text.PlainDocument; public class JTextFieldLimit extends PlainDocument { private int limit; // optional uppercase conversion private boolean toUppercase = false; private int maximo = 500; public JTextFieldLimit(int limit) { super(); if (limit == 0) this.limit = maximo; else this.limit = limit; } public JTextFieldLimit(int limit, boolean upper) { super(); if (limit == 0) this.limit = maximo; else this.limit = limit; toUppercase = upper; } @Override public void insertString(int offset, String str, AttributeSet attr) throws BadLocationException { if (str == null) { return; } if ((getLength() + str.length()) <= limit) { if (toUppercase) { str = str.toUpperCase(); } super.insertString(offset, str, attr); } } }
Esta classe não é nenhuma novidade e pode ser encontrada em vários sites pela internet (na verdade fiz algumas mudanças nela). O que ela faz é permitir a limitação de caracteres e opcionalmente fazer a conversão para maiúsculas. Mas o problema é que pra cada JTextField criado, temos que chamar o método setDocument passando essa classe e os parâmetros. Então para resolver este problema, crie o seguinte método na classe onde estão seus campos de texto:
public void preparaForm() { // JTextFields limitados e com maiúsculas for (Component c : this.getComponents()) { if (c instanceof JTextField) { ((JTextField) c).setDocument(new JTextFieldLimit(((JTextField) c).getColumns(), true)); } } }
Este método deve ser chamado sempre antes de exibir o seu formulário. Ele vai verificar cada componente do formulário e caso este seja do tipo JTextField, será configurado para utilizar o modelo de documento apresentado. Mas onde vou definir o limite de caracteres para cada campo? Observe que o primeiro parâmetro passado para o documento é: ((JTextField) c).getColumns(). Visualmente você poderá definir este número na propriedade column do componente. Mas porque essa propriedade? Isto está parecendo uma bela gambiarra... Fique tranquilo, a propriedade column é apenas um número usado para calcular o tamanho preferido para a largura do campo. Se ele for zero, o tamanho preferido será qualquer um dependendo da implementação do objeto. Isto é, você define a largura visualmente utilizando seu gerenciador de layout preferido e pouco importará o valor definido para a propriedade column.
Enfim, trabalhando desta forma você não precisará ficar escrevendo código para configurar o documento e limite de caracteres para cada campo de texto. Isto não é problema se o projeto é simples, mas se estiver desenvolvendo vários formulários, não é muito produtivo.
Observação: O método só funciona caso esteja trabalhando com JInternalFrames e caso não esteja, pode haver alguma diferença no método que retorna os componentes (this.getComponents). Se for um JDialog por exemplo, ficaria assim:
this.getRootPane().getContentPane().getComponents().
this.getRootPane().getContentPane().getComponents().
Por hoje é só! Qualquer dúvida deixe nos comentários.
Editado em 17/12/2012:
Devido a alguns JTextFields estarem dentro de JPanels e JTabbedPanes, desenvolvi um método recursivo que poderá ser chamado dentro do método preparaForm citado anteriormente:
E a chamada pode ser feita assim:
E aproveito ainda para mostrar como não permitir acentuação nos JTextFields, basta trocar a linha super.insertString(offset, str, attr); da classe JTextFieldLimit por:
Editado em 17/12/2012:
Devido a alguns JTextFields estarem dentro de JPanels e JTabbedPanes, desenvolvi um método recursivo que poderá ser chamado dentro do método preparaForm citado anteriormente:
private void preparaJTextFields(Object obj) { if (obj instanceof JTextField) { ((JTextField) obj).setDocument(new JTextFieldLimit(((JTextField) obj).getColumns(), true)); } if (obj instanceof JPanel) { for (Component c : ((JPanel) obj).getComponents()) { preparaJTextFields(c); } } if (obj instanceof JTabbedPane) { for (Component c : ((JTabbedPane) obj).getComponents()) { preparaJTextFields(c); } } }
E a chamada pode ser feita assim:
public void preparaForm() { //Centraliza o JInternalFrame Dimension d = this.getDesktopPane().getSize(); this.setLocation((d.width - this.getSize().width) / 2, (d.height - this.getSize().height) / 2); //JTextFields limitados preparaJTextFields(this.getContentPane()); }
E aproveito ainda para mostrar como não permitir acentuação nos JTextFields, basta trocar a linha super.insertString(offset, str, attr); da classe JTextFieldLimit por:
//super.insertString(offset, str, attr); // Sem acentos String unaccented = Normalizer.normalize(str, Normalizer.Form.NFD); unaccented = unaccented.replaceAll("[^\\p{ASCII}]", ""); super.insertString(offset, unaccented, attr);
Muito Bom, vlw!
ResponderExcluirObrigado!
ExcluirEu não entendi onde posso limitar tamanhos diferentes para cada um de meus JTextFields, tem como passar um parametro do tipo int por exemplo?
ResponderExcluirOlá, implementando o exemplo que passei, você pode colocar a quantidade desejada na propriedade "column" do seu JTextField. Isso pode ser feito tanto visualmente como via código: textField.setColumns(50);
Excluir@Márcio, até interessante sua implementação, mas..
ResponderExcluirnão posso evitar de aproveitar este espaço para um desabafo, a respeito do SWING p/ variar: realmente componetes como o 'JTextField' (e principalmente o 'JFormmatedTextField') são um negação; não dá para acreditar como tão decepcionante o SWING == uma porcaria.
Pode Delphi não ser melhor q Java, mas, com certeza dá de 10x0 no SWING.
Espero q nós (desenvolvedores Javas) não fiquenos no descaso (agora da mercenária Oracle arght) em relação ao JavaFX as coisas sejam bastante deferentes. :O (foi mal)
Derlon, fique a vontade pois este espaço é pra isso mesmo.
ExcluirNa minha visão, as pessoas que estão acostumadas ao Delphi/VB6, que montam sistemas orientados a eventos só arrastando componentes, não conseguem compreender a profundidade dos componentes Swing. Eles podem parecer complicados a primeira vista, mas estudando melhor, logo se vê o quão poderosos eles são.
Prefiro não entrar na discussão de qual linguagem é melhor, pois como dizem por aí: a melhor linguagem é aquela que você sabe usar. Cada uma vai servir bem em determinadas situações, porém atualmente o Java é uma das linguagem mais utilizadas (ficando pouco atrás do C), enquanto o Delphi está caindo em desuso.
Você disse "agora da mercenária Oracle", mas veja que já fazem mais de 4 anos que a Oracle comprou a Sun.
Olá Márcio!!
ResponderExcluirgostei muito da sua explicação e eu realmente precisava saber dessas informações, mas mesmo assim não consegui editar o numero de caracteres..
ja tentei de todas as formas (e tambem visualmente e nao visualmente) mas de nenhuma forma adiantou.. nao sei mais o que fazer.. nao sei se é minha versao de netbeans(IDE 7.4) que nao permite ou o que.. mas realmente preciso de ajuda (é para meu tcc)
Você me sugere algo??
obrigada!!
Olá, primeiramente me desculpe pela demora em responder. Acredito que seu problema não esteja relacionado a versão do NetBeans, porém sem mais detalhes fica difícil sugerir algo.
Excluir