É 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