Documentos de Académico
Documentos de Profesional
Documentos de Cultura
v. 1.1
Francesc Ross i Albiol
(03/2005)
Todos los que en alguna ocasin nos hemos tenido que enfrentar al desarrollo de interficies de
usuario en Swing nos hemos encontrado con algunas deficiencias en cuanto a los componentes
disponibles. Una de ellas, y creo que importante por su uso masivo en aplicaciones de este tipo, ha
sido la de los campos de entrada.
Hasta la aparicin de la versin 1.4 del JDK, slo disponamos de JTextField. Un componente
bastante limitado que pona de manifiesto las deficiencias de Swing respecto a otras aproximaciones
como, por ejemplo, Delphi.
Siempre he defendido a Swing respecto a las tpicas aproximaciones de Windows haciendo hincapi
en la bondad de su arquitectura y las posibilidades que sta ofrece al desarrollador para extender de
manera relativamente fcil (o, al menos, ortogonal) los componentes que nos ofrece. Fruto de ello
fue la pequea coleccin de widgets que desarroll para JDK 1.2 que inclua, entre otros, un campo
con mscara o campos especializados para nmeros.1 Pero la verdad es que, a pesar de dichas
posibilidades de expansin, si queras algo tan simple como un spinner, te lo tenas que fabricar y
eso siempre da pereza y est sujeto a errores difciles de controlar.
Cuando apareci la versin 1.4 del JDK, tuve la impresin de que Sun haba, de alguna manera,
recogido las quejas de los usuarios y se haba decidido a cubrir algunas de las necesidades bsicas
del desarrollador de interficies de usuario proporcionando, por primera vez en bastante tiempo, dos
componentes bsicos: JSpinner y JFormattedTextField.
Este artculo, como su ttulo indica, pretende profundizar en las posibilidades que nos ofrece
JFormattedTextField.
JFormattedTextField no es ms que una extensin de JTextField que viene a cubrir
algunas de las deficiencias que todos encontrbamos en l.
Un campo de entrada es un componente que cumple una doble funcin. Por una parte, permite que
el usuario entre el texto que se corresponde con un dato solicitado por la aplicacin; y por otra,
permite a la aplicacin mostrar datos al usuario.
La principal limitacin que le encuentro a JTextField es que permite entrar cualquier texto y
que no hay manera fcil de mostrar un texto con un formato concreto. No hay posibilidad de
establecer un control sobre lo que el usuario entra ni manera sencilla de mostrar convenientemente
datos de tipos tan habituales como fechas o nmeros.
Lo primero que uno piensa cuando se acerca por primera vez a JFormattedTextField es
finalmente tenemos un campo que soporta mscaras. Todos esperbamos este componente. Sin
embargo, su nombre no es algo as como JMaskedTextField. Su nombre nos insina que va ms all
de un campo con mscaras. Se trata de un campo de entrada de texto que nos permite especificar
formatos. Ciertamente, una manera de especificar un formato de entrada es mediante una mscara,
pero no es el nico. Adems, como acabo de comentar, un campo de entrada no slo sirve para
1 Algunos de estos widgets se pueden encontrar en mi Web personal
(http://www.froses.com/ES/Descarregues/Widgets.htm).
1 de 24
entrar texto. Tambin muestra lo que hemos entrado. Volveremos ms tarde sobre este punto.
Resumiendo un poco las caractersticas de este componente podemos decir que:
Distingue entre el valor del campo y el texto que lo representa
Permite especificar formatos fijos de entrada de datos, por ejemplo, mediante mscaras
Sabe aprovechar el resto de especificaciones de formato disponibles en Java para nmeros,
fechas, horas, etc.
Permite decidir si se admiten caracteres incorrectos en la entrada o no.
Permite distinguir entre modalidad de edicin y modalidad de visualizacin.
Permite establecer dos modalidades de escritura: insercin y sobrescritura.
Permite que decidamos qu hacer con el foco si lo que el usuario ha entrado no es correcto, al
beneficiarse de las nuevas capacidades del JDK 1.4 para la comprobacin de valores en Swing.
Bueno, creo que las posibilidades que nos ofrece JFormattedTextField son esperanzadoras e
intentar mostrar hasta qu punto.
Para ello, he pensado dividir el artculo en tres partes diferenciadas con objetivos distintos. La
primera, muestra los usos ms habituales de JFormattedTextField y comenta cmo usar la
clase javax.swing.InputVerifier para controlar el foco en base al valor entrado en el
campo. El objetivo, en esta primera parte, es conseguir que el lector pueda utilizar fcilmente
JFormattedTextField en sus aplicaciones.
La segunda discute ms a fondo la arquitectura y el funcionamiento de JFormattedTextField,
y tiene como objetivo preparar al lector para poder extender las posibilidades de
JFormattedTextField, extendindolo y creando nuevos componentes especializados.
En la tercera, presento algunos widgets derivados de JFormattedTextField, y desarrollados
especficamente para este artculo, que tienen un doble objetivo: mostrar al lector una posible va de
expansin del componente que nos ocupa y proporcionarle unos componentes listos para ser usados
en sus aplicaciones. Tambin proporciono algunas aplicaciones que ejemplifican tanto el uso de
estos widgets como de algunos aspectos de JFormattedTexField y de las clases derivadas de
JFormattedTextField.AbstractFormatter.
Qu es JFormattedTextField?
JFormattedTextField es un componente derivado de JTextField que, como ste, sirve
para entrar y mostrar datos.
Una de las caractersticas principales de JFormattedTextField es la de permitir dar formato a
los datos, tanto en el momento de entrarlos como en el de visualizarlos.
Para ello, y a diferencia de JTextField, JFormattedTextField distingue entre el valor
almacenado (una subclase de Object accesible mediante el mtodo getValue()) y el texto que
muestra (una java.lang.String accesible mediante getText()).
En el siguiente apartado, veremos cmo podemos especificar los distintos formatos.
2 de 24
Especificacin de formato
El componente JFormattedTextField nos permite especificar el formato de diversas maneras:
Pero no slo nos presenta la fecha. Nos permite editarla de una manera sencilla y sin error posible.
Si colocamos, por ejemplo, el cursor sobre el mes y pulsamos la flecha hacia arriba, el mes cambia y
pasa a ser sept. Si pulsamos la flecha hacia abajo, el mes ser jul. El mismo comportamiento se da
para el da y el ao. Adems, el comportamiento es inteligente. Supongamos que la fecha sea 28 de
febrero de 2002 y que aumentemos el da. La nueva fecha sera 1 de marzo de 2002. Lgicamente, si
el ao fuera el 2000 (bisiesto) la fecha propuesta sera el 29 de febrero de 2000.
Fijmonos que las partes escribibles se representan con el carcter de subrayado que hemos
especificado con setPlaceholderCharacter().
La siguiente tabla resume los caracteres utilizables en una mscara:
Carcter
Descripcin
Un nmero
Una letra
Cualquier cosa
'
Insertar o sobrescribir
Algo de sumo inters es poder especificar si insertamos o sobrescribimos caracteres. Lo ideal sera
que se pudiera decidir pulsando la tecla <Ins>, pero esto no es inmediato.
El siguiente ejemplo nos indica cmo permitir la sobrescritura:4
2 Los componentes DateField, DecimalField, DecimalFieldScrollable, IntegerField,
MoneyField y PercentField, comentadas ms abajo, ilustran la asignacin de diversos formatos y se incluyen
en el cdigo fuente de este artculo.
3 La aplicacin de ejemplo IntegerFieldTest, comentada ms abajo, nos permite comprobar el funcionamiento
de setAllowsInvalid(boolean).
4 El componente DefaultJFormattedTextField, comentado ms abajo, implementa los mtodos de insercin
y sobrescritura y se incluye en el cdigo fuente de este artculo.
4 de 24
JFormattedTextField efNum =
new JformattedTextField(new DecimalFormat(#,###.00));
NumberFormatter nf = (NumberFormatter)efNum.getFormatter();
nf.setOverrideMode(true);
Editamos en formato ingls (usamos el punto como separador decimal) y sin separadores de
millares.
Visualizamos lo que hemos entrado en el formato de moneda y numrico de nuestro pas. En este
caso, el euro como smbolo de moneda, el punto como separador de millares y la coma como
separador decimal, pero si el programa se ejecutara en Inglaterra, veran el smbolo de la Libra, la
coma sera el separador de millares y el punto, el separador decimal.
5 Los componentes DecimalField, DecimalFieldScrollable, IntegerField, PercentField y
MoneyField, comentadas ms abajo e incluidas en el cdigo fuente de este artculo, ilustran el uso de formatos
distintos para la edicin y la visualizacin.
5 de 24
Si observamos el cdigo, veremos que opto por admitir caracteres incorrectos en edicin. El motivo
es que NumberFormatter define el comportamiento de las teclas ms (+) y menos (-) haciendo
que sean las responsables del cambio de signo. No escriben el signo, sino que lo cambian. Por ello,
y para hacer que la escritura se parezca ms a la que solemos utilizar, he decidido permitir el uso de
caracteres incorrectos en el ejemplo.
La mscara obligar al usuario a entrar ocho dgitos y una letra que ser pasada a maysculas.
Adems, mediante el mtodo setPlaceholderCharacter(), asignamos un carcter de
subrayado para que sirva de pauta al usuario, indicndole las posiciones editables del campo.
El carcter U que vemos en la mscara obligar al usuario a escribir la letra del DNI y pasar dicha
letra a maysculas.
La mscara se encargar, pues, de que el usuario escriba dgitos y letras donde corresponda, pero el
valor entrado no ser entregado al campo directamente hasta que pulsemos la tecla Intro. Al
6 El componente DNIField, cuyo cdigo fuente se incluye, es un ejemplo completo de campo destinado a la entrada
de DNIs.
6 de 24
cambiar de foco, el MaskFormatter no entrega el valor. Hay que decirle explcitamente que si lo
editado es vlido, pase el valor al campo. Para ello, utilizaremos el mtodo
setCommitsOnValidEdit(boolean).
maskDNI.setCommitsOnValidEdit(true);
Si comentamos esta lnea, veremos que al entrar un DNI incorrecto nos deja cambiar el foco debido
a que el valor no se ha entregado al campo para que determine si debe permitir el cambio de foco o
no.
Finalmente, creamos el campo:
JFormattedTextField efDNI = new JformattedTextField(maskDNI);
En este momento, ya hemos dotado a nuestro campo de un cierto control para entrar DNIs:
Nos fuerza a escribir los nmeros y la letra en los lugares que corresponde
Sin embargo, la mscara no nos proporciona todo el control que necesitamos. Si la persona que
entra los datos se equivoca en la letra de control, el error queda registrado. Necesitamos, pues,
impedir que la persona que entra los datos entre un DNI errneo (aunque, y de eso se encarga la
mscara, bien formado).
La versin 1.3 del JDK incorpora un nuevo mtodo a la clase javax.swing.JComponent:
setInputVerifier(InputVerifier v). Este mtodo nos permite asignar a un
JFormattedTextField un algoritmo de control del contenido entrado. Este algoritmo de
control se hallar embebido en una subclase de InputVerifier. La clase InputVerifier es
abstracta y obliga a sus subclases a implementar el mtodo public boolean
verify(JComponent input). Este mtodo devuelve true, si la comprobacin es correcta, o
false, si no lo es.
Veamos ahora la clase derivada de InputVerifier que se encarga de verificar si el DNI entrado
es correcto y permite al campo decidir si autoriza, o no, el cambio de foco.
Disponemos de la clase CIF_NIF, con el mtodo esttico boolean isNIFOK(String DNI)
que nos devuelve true o false en funcin del DNI pasado como parmetro.7
Creamos, por ejemplo, la clase ValidateDNI que extiende InputVerifier:
class ValidateDNI extends InputVerifier {
/**
* Sobrescribimos el mtodo del padre para realizar la
* comprobacin del DNI entrado.
*/
public boolean verify(JComponent input) {
if (input instanceof JFormattedTextField) {
Object o = ((JFormattedTextField)input).getValue();
if (o == null) return true;
String value = o.toString();
return CIF_NIF.isNIFOK(value);
}
return false;
7 de 24
Observaciones generales
JFormattedTextField siempre almacena como valor un objeto (una subclase de Object).
Este valor, sin embargo, debe ser representado como una tira de caracteres (una String) ya que
JFormattedTextField no es sino una subclase de JTextField, quien, como su propio
nombre indica, es un campo de texto.
Esto no es problema para JTextField, ya que siempre almacena objetos de tipo String, pero
para JFormattedTextField no es tan evidente. Alguien tiene que transformar este objeto en
una String para que pueda ser representado.
Volviendo al nombre de nuestro componente, JFormattedTextField, observamos que
contiene el adjetivo formatted (formateado, con formato). Este es un detalle importante. La
transformacin del objeto almacenado a String comporta un proceso de aplicacin de formato.
Resumiendo, JFormattedTextField :
1. Toma el valor que le asignamos,
2. crea una tira de caracteres convenientemente formateada segn algn criterio y
3. la muestra en el campo
Pero hemos comentado ms arriba que el valor no slo se asigna y se ve, sino que se edita. Es decir,
que hay un formato de edicin y que quien controla este formato se encarga de decidir, por ejemplo,
si en tal posicin podemos escribir un nmero o una letra o si podemos escribir o no en una posicin
concreta.
El formato
Los responsables del formato, tanto del de edicin como del de visualizacin, son los
formateadores. Un formateador es, en realidad, una clase derivada de
JFormattedTextField.AbstractFormatter y cumple diversas funciones.
En modo de edicin, decide qu se puede escribir y dnde y cmo y cundo pasa el valor editado al
8 El componente de ejemplo DNIField, descrito ms abajo, se incluye en el cdigo fuente de este artculo.
8 de 24
campo.
Por ejemplo, si usamos un formato numrico, y no permitimos la insercin de caracteres
incorrectos, no podremos teclear ninguna letra. En el campo de DNI que he puesto de ejemplo,
nunca podremos escribir sobre el guin de separacin de la letra de control, a pesar de que
MaskFormatter use el modo de sobrescritura por defecto.
En algunos casos, el formateador tambin define el comportamiento del teclado. Por ejemplo,
DateFormatter permite el incremento o decremento de los distintos campos de una fecha (da,
mes, etc.) mediante las flechas del teclado.
En modo de visualizacin, decide cmo se muestra el valor almacenado en el campo. As, en la
aplicacin de ejemplo MoneyFieldTest, podremos comprobar que el valor almacenado como
BigDecimal en un campo MoneyField, en modo de visualizacin, se muestra como un nmero
y un carcter de moneda.
Un formateador transforma un valor (esto es, un Object) a una tira de caracteres usando el mtodo
valueToString(Object) y una tira de caracteres a un valor (esto es, un Object) usando el
mtodo stringToValue(String). Estos son los mtodos que le permiten almacenar lo
editado como una subclase de Object y mostrar este valor como una tira de caracteres en el
campo.
La siguiente figura muestra la jerarqua de clases de los distintos formateadores:
Tambin se encarga de ajustar la posicin del cursor, situndolo sobre aquellas posiciones en las
que se puede escribir.
NumberFormatter es una subclase de InternationalFormatter diseada especialmente
para la entrada de nmeros.
Entre otras cosas, establece el comportamiento de la tecla <menos> de manera que, estemos donde
estemos del campo, convierte el nmero entrado en negativo.9 La tecla <ms> pasa el nmero a
positivo. Esto es, desaparece el signo menos.
DateFormatter es una subclase de InternationalFormatter diseada especialmente
para la entrada de fechas.
Como hemos comentado ms arriba, define el comportamiento de las flechas del teclado para
aumentar o disminuir das, meses, aos, etc.
La clase MaskFormatter extiende DefaultFormatter y est pensada especialmente para la
edicin de tiras de caracteres con formatos especficos. Como hemos visto ms arriba, se basa en
una mscara que indica qu caracteres se pueden escribir en una posicin determinada.
9 Curiosamente, si no hemos entrado ningn texto o valor y no permitimos la entrada de caracteres incorrectos, pulsar
la tecla <menos> no sirve de nada.
10 En los componentes que he desarrollado de ejemplo, he considerado necesario facilitar el acceso a alguno de los
mtodos de personalizacin de formateadores desde el propio componente. As, por ejemplo, los componentes
ponen a disposicin del programador mtodos como setOverwriteMode(boolean) o
setAllowInvalidCharacters(boolean).
11 Los mtodos setMaximum(Comparable) y setMinimum(Comparable) se han implementado en los
componentes de ejemplo DefaultNumberField, IntegerField, DecimalField. Esto permite establecer
rangos de valores aceptables para instancias de dichos componentes y de sus subclases PercentField y
MoneyField.
12 Vase el mtodo sum(int sign) del componente de ejemplo DefaultNumberField.
10 de 24
A falta de pruebas intensivas, observo que si, habiendo definido un rango de valores aceptable para
un InternationalFormater, asignamos un valor fuera del rango definido mediante el mtodo
setValue(object), no se tiene en cuenta el rango y el valor se asigna sin problemas al
campo.13
MaskFormatter nos obsequia con algunos mtodos realmente tiles:
Asignacin de formatos
La nica manera que tenemos de asignar formatos a un JFormattedTextField es mediante
una subclase de JformattedTextField.AbstractFormatterFactory. Normalmente,
pues, usaremos la nica existente: DefaultFormatterFactory.
DefaultFormatterFactory permite especificar cuatro AbstractFormatters para tres
situaciones distintas:
1. Formato por defecto: Se usa si no hay otro definido para una situacin concreta, lo cual
implica que se usar tanto como formato de edicin como de visualizacin y como nulo, si
13 Esto es debido a las diferencias de comportamiento entre setValue() y commitEdit() que se comentan ms
abajo. Este comportamiento ha sido corregido en los componentes numricos de ejemplo. Si se intenta asignar un
valor fuera de rango, se lanza una IllegalArgumentException.
11 de 24
Los procesos
En el apartado Observaciones generales, he presentado un breve esquema de los principales
procesos que realiza JFormattedTextField para almacenar un valor y mostrarlo. Vamos
ahora a entrar con un poco ms de detalle en estos procesos.
12 de 24
Valor
JFormattedTextField.REVERT
Descripcin
Revierte lo editado al ltimo valor
almacenado en el campo. Es decir, al valor
devuelto por el mtodo getValue(). Si
no hay ningn valor almacenado
previamente o no forzamos un
setValue(), por ejemplo, pulsando
<intro>, el contenido de la edicin
actual se perder.
JFormattedTextField.COMMIT
13 de 24
15 Esta asimetra ha sido corregida para el componente de ejemplo DNIField. El mtodo setValue() llama
siempre al formateador para comprobar errores de formato.
14 de 24
APLICACIONES DE EJEMPLO
Para ilustrar los conceptos tratados en este artculo, he desarrollado una serie de aplicaciones.
Dichas aplicaciones se incluyen con el cdigo fuente correspondiente para que el lector pueda
estudiarlas y modificarlas a su conveniencia.
He procurado que los ejemplos no sean abstractos sino que sean prcticos y usables para cualquier
desarrollador.
He clasificado los ejemplos en tres categoras:
1. Componentes auxiliares: se usan en las aplicaciones de demostracin y tienen poco que ver
con JFormattedTextField. A pesar de ello, creo que algunas de ellas pueden ser
bastante interesantes para los desarrolladores.
2. Componentes derivados de JFormattedTextField: son un conjunto de subclases de
JFormattedTextField que, a mi entender, cumplen un doble objetivo. Por una parte
ilustran la mayor parte de conceptos relacionados con JFormattedTextField y con los
distintos formateadores y por otra, constituyen un conjunto de componentes (en ingls, los
llamaran widgets) especializados en distintas tareas (entrada de nmeros, porcentajes,
fechas y DNIs) listos para ser utilizados por cualquier desarrollador.
La estrategia seguida para el desarrollo de los componentes ha sido doble. Por una parte, he
aadido funcionalidades que no estn directamente relacionadas con JFormattedTextField,
como la aritmtica de fechas, la asignacin de escala a un valor decimal o la
autocomplecin de un DNI y, por otro, he hecho emerger, a nivel de componente,
propiedades del formateador, como la asignacin dinmica del formato de representacin de
fechas o la especificacin de rango para los campos numricos.
3. Aplicaciones de demostracin: se trata de pequeas aplicaciones que ilustran tanto el
funcionamiento de los distintos componentes descritos en el punto anterior, como el de
algunos aspectos de JFormattedTextField y de los formateadores.
A continuacin, paso a describir brevemente cada una de ellas.
Componentes auxiliares
CIF_NIF
Es una clase que proporciona una serie de mtodos estticos para la verificacin de CIFs y NIFs
espaoles. Contiene una amplia documentacin sobre las fuentes en las que me he basado para
escribirla y la casustica que se trata.
Destacara las siguientes funcionalidades:
BoundJSpinner
Es una subclase de JSpinner que tiene la propiedad value bound. Esto es, cada vez que el valor
15 de 24
ButtonGroupJPanel
Es una subclase de JPanel que facilita el uso de JRadioButons desde un editor visual.
Si queremos un comportamiento normal de mutua exclusin de JRadioButons (esto es, que
cuando se pulse en uno el que estaba seleccionado deje de estarlo), es necesario aadir todos los
JRadioButons a un ButtonGroup. ButtonGroupPanel, se encarga de ello por nosotros.
ButtonGroupPanel est basado en un ejemplo de Scott Stanchfield (http://www.javadude.com)
y se usa en las demostraciones de algunos componentes.
OverwriteCaret
Es una subclase de DefaultCaret que dibuja un cursor horizontal. Se utiliza para indicar que
estamos en modalidad de sobrescritura.
Pair
Un simple bean no visual que mantiene una pareja de tipo clave/descripcin. Se usa en los
JCombobox de algunas de las demostraciones de los componentes.
EnhancedJFormattedTextField
Es una interface que establece los mtodos, y por ende las funcionalidades, generales del conjunto
de componentes.
DefaultJFormattedTextField
Es una subclase abstracta de JFormattedTextField que implementa la interface
EnhancedJFormattedTextField y que contiene cdigo para funcionalidades comunes al
resto de los componentes. Destaco las siguientes:
La asignacin de dicha funcionalidad a la tecla <ins>, que intercambia las dos modalidades
de escritura.
16 A pesar de haber realizado una infinitud de pruebas y de disear y ejecutar pruebas unitarias, puede que los
componentes no se comporten como debieran. Los proporciono a guisa de ejemplos y no me responsabilizo de los
efectos colaterales que se deriven de su uso en produccin.
16 de 24
DefaultNumberField
Es una subclase abstracta de DefaultJFormattedTextField que contiene cdigo para las
funcionalidades comunes de los campos numricos (DecimalField, IntegerField,
MoneyField y PercentField). Por ejemplo, define el comportamiento del teclado para que
las flechas sirvan para incrementar o decrementar el valor almacenado en el campo o permite
establecer un rango de valores para los componentes numricos.
DecimalField
Extiende DefaultNumberField adaptndolo a la presentacin y edicin de nmeros decimales.
Destacar las siguientes funcionalidades:
Se le puede asignar cualquier valor derivado de Number, pero tambin valores de tipos
nativos (int, long, byte, short, float, double, etc.). Internamente, se almacenan
como BigDecimals
IntegerField
Es una subclase de DefaultNumberField que facilita la edicin y presentacin de nmeros
enteros.
Se le puede asignar cualquier valor derivado de Number (si el valor tiene decimales, slo se toma
la parte entera) pero tambin valores de tipos nativos (int, long, byte, short, float,
double, etc.). Internamente, se almacenan como BigInteger.
MoneyField
Extiende DecimalField asignando como formato de visualizacin el de moneda.
PercentField
Extiende DecimalField asignando como formato de visualizacin el de porcentaje.
17 de 24
DNIField
Es una subclase de DefaultJFormattedTextField que facilita la entrada y validacin de
DNIs espaoles mediante una mscara de entrada.
Funcionalidades destacables:
DateField
Es una subclase de DefaultFormattedTextField que facilita la entrada, visualizacin y
manejo de fechas y horas.
Destaco las siguientes funcionalidades:
Implementa una aritmtica simple de fechas. Permite aadir o quitar das, semanas, meses,
aos, horas, minutos o segundos a la fecha almacenada como valor en el campo de manera
sencilla (p.e. addMonths(3), aadira tres meses, addWeeks(-3) restara tres semanas
a la fecha).
StringField
Extiende DefaultFormattedTextField para facilitar la escritura de texto.
Si bien Swing nos proporciona ya un campo de texto, JTextField, considero que no es suficiente
para cubir algunas de las necesidades ms importantes de un campo de este estilo. As, por ejemplo,
JTextField slo nos proporciona un mtodo de escritura, la insercin, y no nos permite
determinar la longitud mxima del texto a escribir.
Este segundo aspecto es importante si tenemos ligado el texto a alguna columna de una tabla en una
base de datos. Si usamos JTextField, no podemos asegurar que el texto entrado por el usuario
tenga una longitud inferior o igual a la definida para la columna de la tabla, por lo que nos veremos
obligados ha controlar este hecho por programa. StringField nos permite delegar en la
interficie dicho control al permitirnos determinar la longitud mxima admisible para el texto.
StringField nos permite, tambin, establecer una poltica de recorte para la asignacin de
valor. Si la activamos, usando el mtodo setStripOn(boolean), al intentar asignar un valor
con una longitud superior a la permitida, ste ser recortado convenientemente antes de ser
asignado. Si no la tenemos activada, consecuentemente, lanzar una
IllegalArgumentException al intentar asignar un valor con una longitud superior a la
permitida.
18 de 24
Aplicaciones de demostracin
Siempre se ha dicho que una imagen (en nuestro caso, una aplicacin visual) vale ms que mil
palabras. Es por este motivo que he creado una serie de aplicaciones de escritorio que pretenden
ejemplificar las funcionalidades de cada uno de los componentes comentados en el apartado
anterior.
As, pues, el lector dispone de un ejemplo de uso para cada uno de los componentes derivados de
JFormattedTextField:
Estas aplicaciones se pueden ejecutar por separado o bien a travs de la clase Pruebas que nos
permite decidir qu aplicacin ejecutar.
Los ejemplos de uso son, creo, bastante intuitivos, sin embargo, hay algunos trucos poco evidentes:
En la aplicacin DNIFieldTest, no hace falta escribir siempre la letra del DNI, si se han
entrado todos los nmeros del DNI, basta con pulsar Ctrl-Espacio y la letra correcta
aparecer por arte de magia.
Si lo que sucede es que la letra entrada es incorrecta, tambin se puede recurrir a
Ctrl-Espacio para que se cambie por la correcta.
19 de 24
Arquitectura de clases
La siguiente figura nos muestra el diagrama de clases de los componentes de ejemplo derivados de
JformattedTextField. Tngase en cuenta que el diagrama no incluye todos los mtodos.
20 de 24
21 de 24
EPLOGO
Es notable el aparente cambio de estrategia de Sun proporcionando en la versin 1.4 de Java dos
nuevos componentes Swing que intentan cubrir vacos importantes en lo que al desarrollo de
interficies grficas se refiere. Lamentablemente, la versin 5.0 no incluye ningn componente nuevo
ni mejora los anteriores.
JFormattedTextField nos permite desarrollar aplicaciones ms profesionales y mejora la
imagen de Swing. Tenemos mscaras, campos de fecha con un comportamiento razonable, podemos
usar diversos formateadores para personalizar nuestros campos, etc.
Sin embargo, durante el tiempo que me ha llevado construir este artculo, he encontrado algunos
obstculos que me han dificultado la labor de escribir tanto el texto del artculo como los
componentes de ejemplo.
He encontrado, y es una opinin personal, problemas de ortogonalidad, algunos de los cuales ya he
expuesto, como la diferencia de comportamiento de commitEdit() y setValue() que,
combinados con la admisin o no de literales en el valor del MaskFormatter, me han dado algn
que otro quebradero de cabeza. En el mismo orden de cosas estara el establecimiento de rangos de
InternationalFormatter.
Siguiendo con la ortogonalidad, me pregunto dnde est el model de JformattedTextField?
Ciertamente, sigue siendo el mismo que el de su padre, JTextField, un PlainDocument. Sin
embargo, las relaciones entre vista/controlador (delegate) y modelo, ni son tan claras como en
JTextField ni se cuentan en parte alguna.
Me he encontrado tambin con problemas de visibilidad (scope) cuando he intentado extender, por
ejemplo, DefaultFormatter. Hay mtodos importantes de DefaultFormatter y de
JTextComponent que slo estn visibles a nivel de package y que dificultan extender tanto
DefaultFormatter como AbstractFormatter. Es realmente complejo extender los
formateadores que nos vienen dados.
En el proceso de creacin de este artculo, me propuse reproducir un componente que haba
desarrollado hace tiempo como una extensin de JTextField y que ofreca una funcionalidad
sencilla pero prctica: determinar el nmero mximo de caracteres que poda aceptar un campo de
entrada.
Ante la dificultad de extender DefaultFormatter, decid ir directamente a PlainDocument
y atacar el modelo como hice anteriormente. Bien, no acab de funcionar. El mtodo
insertString() de AbstractDocument no se invoca al insertar una tira (por teclado o
desde el clipboard) como en JTextField, sino cuando el campo cambia de foco. La falta de
tiempo y las dificultades han hecho que abandonara esta lnea. Finalmente, y para la versin 1.1 de
este artculo, he desarrollado StringField, pero recurriendo al control de la propiedad value,
ya que las otras vas, a mi entender ms coherentes, han resultado imposibles de seguir
(posiblemente por mis limitaciones personales).
A pesar de los pesares, creo que JFormattedTextField es un componente importante que
debe formar parte, de manera habitual, en nuestras aplicaciones.
Deseo que el lector pueda, con la ayuda de este artculo, sortear mejor que yo las dificultades de
creacin de componentes derivados de JFormattedTextField y que este artculo contribuya a
hacer un mejor y mayor uso de Swing en sus aplicaciones de escritorio.
22 de 24
QU HE USADO?
He usado Eclipse 3.0.1 (http://www.eclipse.org) para el desarrollo, la generacin de Javadocs y las
pruebas unitarias con JUnit 3.8.1 (http://www.junit.org).
Para el desarrollo de las interficies de usuario en Swing, he usado el Visual Editor de Eclipse
(http://www.eclipse.org/vep/) en su versin 1.0.2.1RC2.
Para la generacin del diagrama de clases de los componentes, he usado la ltima versin del plugin
de Eclipse Omondo EclipseUML (http://www.omondo.com/index.html).
Este artculo ha sido escrito con OpenOffice 2.0 beta (http://www.openoffice.org/) y ste tambin se
ha usado para la generacin del PDF.
QU HE LEDO?
Realmente, hay poca literatura que haga referencia a JformattedTextField. Yo slo he
encontrado un par de tutoriales que cubren los aspectos ms bsicos.
El primero, siempre es una referencia, es el captulo How to Use Formatted Text Fields
(http://java.sun.com/docs/books/tutorial/uiswing/components/formattedtextfield.html) del tutorial
oficial de Java. Es correcto, pero creo que insuficiente si quieres trabajar a fondo con las
posibilidades de JformattedTextField. Expone con claridad algunos conceptos bsicos.
El segundo, es el artculo de John Zukowski Swing's new JFormattedTextField component
(http://www-106.ibm.com/developerworks/java/library/j-mer0625/) de junio de 2002 dentro de la
interesante serie de artculos sobre novedades de la versin 1.4 de Java Magic with Merlin que el
autor ha publicado en developerWorks. Bien escrito pero muy bsico.
Como he comentado ms arriba, para entender el funcionamiento de JFormattedTextField,
he tenido que leer mucha API y bastante cdigo fuente.
El archivo LEEME.TXT que explica, como aqu, qu contiene el directorio y cmo se usa.
o bien
java -jar jftf.jar
BoundJSpinner
ButtonGroupJPanel
OverwriteCaret
24 de 24