Está en la página 1de 24

USOS INTERESANTES DE JFormattedTextField

v. 1.1 Francesc Ross i Albiol !"#$!!%&


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. del !"#, slo dispon$amos de JTextField. Un componente bastante limitado que pon$a de manifiesto las deficiencias de Swing respecto a otras apro%imaciones como, por e&emplo, "elphi. Siempre he defendido a Swing respecto a las t$picas apro%imaciones de 'indows haciendo hincapi( en la bondad de su arquitectura y las posibilidades que (sta ofrece al desarrollador para e%tender de manera relativamente f)cil *o, al menos, ortogonal+ los componentes que nos ofrece. ,ruto de ello fue la peque-a coleccin de widgets que desarroll( para !"# 1.. que inclu$a, entre otros, un campo con m)scara o campos especiali/ados para n0meros.1 1ero la verdad es que, a pesar de dichas posibilidades de e%pansin, si quer$as algo tan simple como un spinner, te lo ten$as que fabricar y eso siempre da pere/a y est) su&eto a errores dif$ciles de controlar. 2uando apareci la versin 1. del !"#, tuve la impresin de que Sun hab$a, de alguna manera, recogido las que&as de los usuarios y se hab$a decidido a cubrir algunas de las necesidades b)sicas del desarrollador de interficies de usuario proporcionando, por primera ve/ en bastante tiempo, dos componentes b)sicos3 JSpinner y JFormattedTextField. 4ste art$culo, como su t$tulo indica, pretende profundi/ar en las posibilidades que nos ofrece JFormattedTextField. JFormattedTextField no es m)s que una e%tensin de JTextField que viene a cubrir algunas de las deficiencias que todos encontr)bamos en (l. Un campo de entrada es un componente que cumple una doble funcin. 1or una parte, permite que el usuario entre el te%to que se corresponde con un dato solicitado por la aplicacin5 y por otra, permite a la aplicacin mostrar datos al usuario. 6a principal limitacin que le encuentro a JTextField es que permite entrar cualquier te%to y que no hay manera f)cil de mostrar un te%to con un formato concreto. 7o 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 n0meros. 6o primero que uno piensa cuando se acerca por primera ve/ a JFormattedTextField es 8finalmente tenemos un campo que soporta mscaras. Todos esper)bamos este componente. Sin embargo, su nombre no es algo as$ como JMaskedTextField. Su nombre nos insin0a que va m)s all) de un campo con m)scaras. Se trata de un campo de entrada de te%to que nos permite especificar formatos. 2iertamente, una manera de especificar un formato de entrada es mediante una m)scara, pero no es el 0nico. 9dem)s, como acabo de comentar, un campo de entrada no slo sirve para
1 9lgunos de estos widgets se pueden encontrar en mi 'eb personal *http3::www.froses.com:4S:"escarregues:'idgets.htm+.

1 de .

entrar te%to. Tambi(n muestra lo que hemos entrado. ;olveremos m)s tarde sobre este punto. <esumiendo un poco las caracter$sticas de este componente podemos decir que3 "istingue entre el valor del campo y el te%to que lo representa 1ermite especificar formatos fi&os de entrada de datos, por e&emplo, mediante m)scaras Sabe aprovechar el resto de especificaciones de formato disponibles en !ava para n0meros, fechas, horas, etc. 1ermite decidir si se admiten caracteres incorrectos en la entrada o no. 1ermite distinguir entre modalidad de edicin y modalidad de visuali/acin. 1ermite establecer dos modalidades de escritura3 insercin y sobrescritura. 1ermite que decidamos qu( hacer con el foco si lo que el usuario ha entrado no es correcto, al beneficiarse de las nuevas capacidades del !"# 1. para la comprobacin de valores en Swing. =ueno, creo que las posibilidades que nos ofrece JFormattedTextField son esperan/adoras e intentar( mostrar hasta qu( punto. 1ara ello, he pensado dividir el art$culo en tres partes diferenciadas con ob&etivos distintos. 6a primera, muestra los usos m)s habituales de JFormattedTextField y comenta cmo usar la clase javax.swing.InputVerifier para controlar el foco en base al valor entrado en el campo. 4l ob&etivo, en esta primera parte, es conseguir que el lector pueda utili/ar f)cilmente JFormattedTextField en sus aplicaciones. 6a segunda discute m)s a fondo la arquitectura y el funcionamiento de JFormattedTextField, y tiene como ob&etivo preparar al lector para poder e%tender las posibilidades de JFormattedTextField, e%tendi(ndolo y creando nuevos componentes especiali/ados. 4n la tercera, presento algunos widgets derivados de JFormattedTextField, y desarrollados espec$ficamente para este art$culo, que tienen un doble ob&etivo3 mostrar al lector una posible v$a de e%pansin del componente que nos ocupa y proporcionarle unos componentes listos para ser usados en sus aplicaciones. Tambi(n proporciono algunas aplicaciones que e&emplifican tanto el uso de estos widgets como de algunos aspectos de JFormattedTexField y de las clases derivadas de JFormattedTextField.AbstractFormatter.

USOS 'ENERA(ES DE JFormattedTextField


2omo he comentado m)s arriba, el ob&etivo de este cap$tulo es proporcionar la informacin suficiente al lector para que pueda hacer uso de las principales funcionalidades de JFormattedTextField.

)*+ es JFormattedTextField,
JFormattedTextField es un componente derivado de JTextField que, como (ste, sirve para entrar y mostrar datos. Una de las caracter$sticas principales de JFormattedTextField es la de permitir dar formato a los datos, tanto en el momento de entrarlos como en el de visuali/arlos. 1ara ello, y a diferencia de JTextField, JFormattedTextField distingue entre el valor almacenado *una subclase de Object accesible mediante el m(todo getValue( + y el te%to que muestra *una java.lang.String accesible mediante getText( +. 4n el siguiente apartado, veremos cmo podemos especificar los distintos formatos.

. de .

Es-eci.icaci/n de .ormato
4l componente JFormattedTextField nos permite especificar el formato de diversas maneras3

De manera a+tom0tica1 Asi2nando +n valor al cam-o


Simplemente asignando un valor al campo, (ste nos asigna un formato. 9s$, por e&emplo, si le asignamos una fecha, (l nos la permitir) editar. 4l siguiente cdigo crea un campo de entrada para fechas con el formato por defecto3
JFormattedTextField!efFec"a!#!new!JFormattedTextField(new!$ate( %

4l campo mostrar) la fecha actual con el siguiente formato3


&'(ago()**)

1ero no slo nos presenta la fecha. 7os permite editarla de una manera sencilla y sin error posible. Si colocamos, por e&emplo, el cursor sobre el mes y pulsamos la flecha hacia arriba, el mes cambia y pasa a ser sept. Si pulsamos la flecha hacia aba&o, el mes ser) jul. 4l mismo comportamiento se da para el d$a y el a-o. 9dem)s, el comportamiento es inteligente. Supongamos que la fecha sea .> de febrero de .??. y que aumentemos el d$a. 6a nueva fecha ser$a 1 de mar/o de .??.. 6gicamente, si el a-o fuera el .??? *bisiesto+ la fecha propuesta ser$a el .@ de febrero de .???.

3ediante +na m0scara


1odemos utili/ar una m)scara para determinar el formato. 1or e&emplo, si quisi(ramos crear un campo para entrar cdigos de cuenta corriente, podr$amos hacerlo as$ de f)cil3
+as,Formatter!mf--!#!new!+as,Formatter(.////(////(//(//////////0 % mf--.set1lace"older-"aracter(232 % JFormattedTextField!ef--!#!new!JformattedTextField(mf-- %

4l campo tendr$a el siguiente aspecto3


3333(3333(33(3333333333

,i&(monos que las partes escribibles se representan con el car)cter de subrayado que hemos especificado con set1lace"older-"aracter( . 6a siguiente tabla resume los caracteres utili/ables en una m)scara3

4ar0cter
A B 9 C U 6 H E Un n0mero Una letra

Descri-ci/n

Una letra o un n0mero 2ualquier cosa Una letra que ser) pasada a may0scula Una letra que ser) pasada a min0scula Un d$gito he%adecimal *9D,, aDf, ?D@+ 2ar)cter de escape para otro car)cter de m)scara

3ediante descri-tores de .ormato 5a existentes


!ava nos ofrece una amplia gama de especificaciones de formato para fechas, horas, n0meros y monedas. Todos ellos pueden ser utili/ados, directa o indirectamente, para especificar el formato F de .

usado por el campo. 4&emplificaremos algunos de ellos. G)s arriba, hemos mostrado cmo especificar un formato de fecha simplemente pasando una al constructor del campo. 4l resultado es vistoso, pero cualquier persona que entre datos nos dir) que es poco pr)ctico. Ser$a m)s interesante algo del estilo de dd4mm4aa. 4l siguiente cdigo nos muestra cmo hacerlo3.
JFormattedTextField!efFec"a!#! !!new!JFormattedTextField(new!Simple$ateFormat(.dd4++4550 %

4l resultado obtenido ser$a3 1@:?>:?.. 4l comportamiento de las flechas ser$a el ya descrito. Si lo que pretendemos es entrar un n0mero con un m)%imo de dos decimales3
JFormattedTextField!ef6um!#! !!new!JformattedTextField(new!$ecimalFormat(./7///.**0 %

Si nos interesa que el usuario entre importes en euros en nuestro campo3


JFormattedTextField!ef+on!#! !!new!JformattedTextField(6umberFormat.get-urrenc5Instance( ef+on.setValue(new!Integer(&*** % %

6o que ver$amos ser$a3


&.***7**!8

Admitir o no caracteres incorrectos


9 veces, nos puede interesar permitir que el usuario pueda entrar caracteres incorrectos. 1ara hacerlo, usaremos formateadores propios de JFormattedTextField. ;eamos el siguiente e&emplo3F
JFormattedTextField!ef6um!#! !!new!JformattedTextField(new!$ecimalFormat(./7///.**0 % 6umberFormatter!nf!#!(6umberFormatter ef6um.getFormatter( % nf.setAllowsInvalid(true)%

"isponemos de tres formateadores especiales derivados todos ellos de la clase javax.swing.JFormattedTextField.AbstractFormatter3 !! +as,Formatter H Utili/ado para m)scaras y derivado directamente de AbstractFormatter. 6umberFormatter !! H Utili/ado para n0meros y derivado de una subclase de AbstractFormatter3 InternationalFormatter. $ateFormatter !! H Utili/ado para fechas y horas y derivado, como el anterior, de InternationalFormatter.

Insertar o sobrescribir
9lgo de sumo inter(s es poder especificar si insertamos o sobrescribimos caracteres. 6o ideal ser$a que se pudiera decidir pulsando la tecla 9Ins:, pero esto no es inmediato. 4l siguiente e&emplo nos indica cmo permitir la sobrescritura3
. 6os componentes $ateField, $ecimalField, $ecimalFieldScrollable, IntegerField, +one5Field y 1ercentField, comentadas m)s aba&o, ilustran la asignacin de diversos formatos y se incluyen en el cdigo fuente de este art$culo. F 6a aplicacin de e&emplo IntegerFieldTest, comentada m)s aba&o, nos permite comprobar el funcionamiento de setAllowsInvalid(boolean . 4l componente $efaultJFormattedTextField, comentado m)s aba&o, implementa los m(todos de insercin y sobrescritura y se incluye en el cdigo fuente de este art$culo.

de .

JFormattedTextField!ef6um!#! !!new!JformattedTextField(new!$ecimalFormat(./7///.**0 % 6umberFormatter!nf!#!(6umberFormatter ef6um.getFormatter( % nf.setOverride+ode(true %

3odalidad de edici/n 5 de vis+ali6aci/n


Imaginemos que tenemos un campo para entrar importes en euros como el que hemos descrito m)s arriba. 4l resultado obtenido es interesante5 se ve bien, con el s$mbolo de euro al final y los separadores de millares y la coma decimal siguiendo las directrices de nuestro pa$s. 1ero una ve/ m)s, un usuario que se dedique a entrar datos nos dir$a que es incmodo. 7ormalmente, se usa el teclado num(rico y uno no tiene que ir a buscar la coma al teclado alfanum(rico. Usa un punto para indicar la coma. 2laro que si bien es pr)ctico entrar &);<.;=, queda mal cuando se visuali/a. Tenemos, pues, un conflicto3 lo que es pr)ctico para la entrada de datos no es claro en la visuali/acin. JFormattedTextField nos permite resolver este conflicto especificando un formato para la edicin y otro para la visuali/acin. 2uando el foco est( en el campo, usar) el de edicin y cuando (ste pierda el foco, usar) el de visuali/acin.J ;eamos cmo hacerlo para nuestro campo de importes en euros3
44!Creamos el campo JFormattedTextField!ef$ecimal!# !!!new!JformattedTextField( % 44!Formato de visualizacin 6umberFormat!dispFormat!#!6umberFormat.get-urrenc5Instance( % 44!Formato de edicin: ingls (separador decimal: el punto) 6umberFormat!editFormat!# !!!!!!!!!!!!!!!!6umberFormat.get6umberInstance(>ocale.?6@>ISA % 44!Para la edicin, no queremos separadores de millares editFormat.set@roupingBsed(false % 44!Creamos los formateadores de nmeros 6umberFormatter!dnFormat!#!new!6umberFormatter(dispFormat % 6umberFormatter!enFormat!#!new!6umberFormatter(editFormat % 44!Creamos la factora de formateadores especificando los 44!formateadores por defecto, de visualizacin de edicin $efaultFormatterFactor5!currFactor5!#! new!$efaultFormatterFactor5(dnFormat7!dnFormat7!enFormat % 44!!l formateador de edicin admite caracteres incorrectos enFormat.setAllowsInvalid(true % 44!Asignamos!la!factorCa!al!campo ef$ecimal.setFormatterFactor5(currFactor5 %

4ditamos en formato ingl(s *usamos el punto como separador decimal+ y sin separadores de millares. ;isuali/amos lo que hemos entrado en el formato de moneda y num(rico de nuestro pa$s. 4n este caso, el euro como s$mbolo de moneda, el punto como separador de millares y la coma como separador decimal, pero si el programa se e&ecutara en Inglaterra, ver$an el s$mbolo de la 6ibra, la coma ser$a el separador de millares y el punto, el separador decimal.
J 6os componentes $ecimalField, $ecimalFieldScrollable, IntegerField, 1ercentField y +one5Field, comentadas m)s aba&o e incluidas en el cdigo fuente de este art$culo, ilustran el uso de formatos distintos para la edicin y la visuali/acin.

J de .

6a siguiente imagen muestra nuestro campo en modalidad de edicin3

6a siguiente imagen muestra el mismo campo en modalidad de visuali/acin3

Si observamos el cdigo, veremos que opto por admitir caracteres incorrectos en edicin. 4l motivo es que 6umberFormatter define el comportamiento de las teclas m)s *D+ y menos *(+ haciendo que sean las responsables del cambio de signo. 7o escriben el signo, sino que lo cambian. 1or ello, y para hacer que la escritura se pare/ca m)s a la que solemos utili/ar, he decidido permitir el uso de caracteres 8incorrectosK en el e&emplo.

4ontrol del .oco1 InputVerifier


Uno de los problemas t$picos en el desarrollo de interficies gr)ficas para la entrada de datos es decidir qu( se hace cuando el usuario que ha rellenado incorrectamente un campo quiere pasar al siguiente. 4n algunos casos nos puede interesar que lo pueda hacer, pero en otros no. Imaginemos que necesitamos un campo para entrar n0meros de "7I, con su letra. 4ste campo, en nuestra aplicacin, es clave ya que a partir de (l, se obtiene el resto de la informacin. 9s$, pues, si el n0mero entrado fuera incorrecto, no debi(ramos permitir que el usuario saltara al campo siguiente. 9nteriormente, hab$a que utili/ar alg0n truco *que no viene al caso+ para evitar que el foco se fuera al siguiente componente. 4n la versin 1.F del !"#, se nos facilita bastante el traba&o. 1odemos asignar al campo una clase que e%tienda InputVerifier mediante el m(todo set"nput#erifier() de manera que sea esta clase la que controle si el usuario podr) salir del campo *pasar el foco a otro componente+ o no. 1ara seguir con el e&emplo del "7I, proponemos un peque-o e&emplo que ilustre el procedimiento.L ;amos a definir una m)scara que facilite la entrada de "7Is en nuestro campo3
44!$efiniciEn!de!la!mFscara!de!$6I +as,Formatter!mas,$6I!#!null% tr5!G !!mas,$6I!#!new!+as,Formatter(H//.///.///(BH % I!catc"!(1arse?xception!e !G !!!!44!$e!momento7!no!"acemos!nada !!I 44!?l!carJcter!a!mostrar!en!las!posiciones!escribibles!es!el 44!subra5ado. mas,$6I.set1lace"older-"aracter(232 %

6a m)scara obligar) al usuario a entrar ocho d$gitos y una letra que ser) pasada a may0sculas. 9dem)s, mediante el m(todo set1lace"older-"aracter( , asignamos un car)cter de subrayado para que sirva de pauta al usuario, indic)ndole las posiciones editables del campo. 4l car)cter U que vemos en la m)scara obligar) al usuario a escribir la letra del "7I y pasar) dicha letra a may0sculas. 6a m)scara se encargar), pues, de que el usuario escriba d$gitos y letras donde corresponda, pero el valor entrado no ser) entregado al campo directamente hasta que pulsemos la tecla Intro. 9l
L 4l componente $6IField, cuyo cdigo fuente se incluye, es un e&emplo completo de campo destinado a la entrada de "7Is.

L de .

cambiar de foco, el +as,Formatter no entrega el valor. Hay que decirle e%pl$citamente que si lo editado es v)lido, pase el valor al campo. 1ara ello, utili/aremos el m(todo set-ommitsOnValid?dit(boolean .
mas,$6I.set-ommitsOnValid?dit(true %

Si comentamos esta l$nea, veremos que al entrar un "7I incorrecto nos de&a 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. ,inalmente, creamos el campo3
JFormattedTextField!ef$6I!#!new!JformattedTextField(mas,$6I %

4n este momento, ya hemos dotado a nuestro campo de un cierto control para entrar "7Is3

7os fuer/a a escribir los n0meros y la letra en los lugares que corresponde 1asa autom)ticamente la letra final de control a may0sculas

Sin embargo, la m)scara 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. 7ecesitamos, pues, impedir que la persona que entra los datos entre un "7I errneo *aunque, y de eso se encarga la m)scara, bien formado+. 6a versin 1.F del !"# incorpora un nuevo m(todo a la clase javax.swing.J-omponent3 setInputVerifier(InputVerifier!v . 4ste m(todo nos permite asignar a un JFormattedTextField un algoritmo de control del contenido entrado. 4ste algoritmo de control se hallar) embebido en una subclase de InputVerifier. 6a clase InputVerifier es abstracta y obliga a sus subclases a implementar el m(todo public!boolean! verif5(J-omponent!input . 4ste m(todo devuelve true, si la comprobacin es correcta, o false, si no lo es. ;eamos ahora la clase derivada de InputVerifier que se encarga de verificar si el "7I entrado es correcto y permite al campo decidir si autori/a, o no, el cambio de foco. "isponemos de la clase -IF36IF, con el m(todo est)tico boolean!is6IFOK(String!$6I ! que nos devuelve true o false en funcin del "7I pasado como par)metro.M 2reamos, por e&emplo, la clase Validate$6I que e%tiende InputVerifier3
class!Validate$6I!extends!InputVerifier!G 4LL !L!Sobrescribimos!el!mMtodo!del!padre!para!realiNar!la! !L!comprobaciEn!del!$6I!entrado. !L4 public!boolean!verif5(J-omponent!input !G !!if!(input!instanceof!JFormattedTextField !G !!!!Object!o!#!((JFormattedTextField input .getValue( % !!!!if!(o!##!null !return!true% !!!!String!value!#!o.toString( % !!!!return!-IF36IF.is6IFOK(value % !!I !!return!false% I

4l m(todo verif5( se encarga de llamar al m(todo -I@36IF.is6IFOK( que contiene el algoritmo de verificacin de "7Is. Si este m(todo da el "7I por bueno, el usuario podr) cambiar el
M 6a clase -IF36IF, comentada m)s aba&o, se incluye en el cdigo fuente de este art$culo.

M de .

foco. Si no es as$, el foco permanecer) en el campo de "7I.>

)473O FUN4IONA EN REA(IDAD,


4n la primera parte de este art$culo he intentado que el lector disponga de la informacin suficiente sobre JFormattedTextField para que se anime a usarlo en sus aplicaciones. =uena parte de la informacin que el lector ha encontrado en la primera parte puede, tambi(n, encontrarla en diversos tutoriales. 4l de Sun, por e&emplo, nos muestra algunos e&emplos parecidos a los que he descrito. Sin embargo, ni sus e&emplos, ni los que yo he presentado son realmente serios. Simplemente pretenden ilustrar algunas de las funcionalidades b)sicas de los distintos elementos implicados en JFormattedTextField. 1ara esta segunda parte, me he propuesto intentar proporcionar a lector la informacin necesaria para poder usar aquellos aspectos poco evidentes de JFormattedTextField. 6a informacin que aqu$ presento es fruto del estudio directo de las distintas 91Is implicadas en JFormattedTextField y del cdigo fuente de las distintas clases. 4spero que le ahorre traba&o al lector.

Observaciones 2enerales
JFormattedTextField siempre almacena como valor un ob&eto *una subclase de Object+. 4ste 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 te%to. 4sto no es problema para JTextField, ya que siempre almacena ob&etos de tipo String, pero para JFormattedTextField no es tan evidente. 9lguien tiene que transformar este ob&eto en una String para que pueda ser representado. ;olviendo al nombre de nuestro componente, JFormattedTextField, observamos que contiene el ad&etivo formatted *formateado, con formato+. 4ste es un detalle importante. 6a transformacin del ob&eto almacenado a String comporta un proceso de aplicacin de formato. <esumiendo, JFormattedTextField 3 1. Toma el valor que le asignamos, .. crea una tira de caracteres convenientemente formateada seg0n alg0n criterio y F. la muestra en el campo 1ero hemos comentado m)s arriba que el valor no slo se asigna y se ve, sino que se edita. 4s decir, que hay un formato de edicin y que quien controla este formato se encarga de decidir, por e&emplo, si en tal posicin podemos escribir un n0mero o una letra o si podemos escribir o no en una posicin concreta.

El .ormato
6os responsables del formato, tanto del de edicin como del de visuali/acin, son los formateadores. Un formateador es, en realidad, una clase derivada de JFormattedTextField.AbstractFormatter y cumple diversas funciones. 4n modo de edicin, decide qu( se puede escribir y dnde y cmo y cu)ndo pasa el valor editado al
> 4l componente de e&emplo $6IField, descrito m)s aba&o, se incluye en el cdigo fuente de este art$culo.

> de .

campo. 1or e&emplo, si usamos un formato num(rico, y no permitimos la insercin de caracteres incorrectos, no podremos teclear ninguna letra. 4n el campo de "7I que he puesto de e&emplo, nunca podremos escribir sobre el guin de separacin de la letra de control, a pesar de que +as,Formatter use el modo de sobrescritura por defecto. 4n algunos casos, el formateador tambi(n define el comportamiento del teclado. 1or e&emplo, $ateFormatter permite el incremento o decremento de los distintos campos de una fecha *d$a, mes, etc.+ mediante las flechas del teclado. 4n modo de visuali/acin, decide cmo se muestra el valor almacenado en el campo. 9s$, en la aplicacin de e&emplo +one5FieldTest, podremos comprobar que el valor almacenado como Oig$ecimal en un campo +one5Field, en modo de visuali/acin, se muestra como un n0mero y un car)cter de moneda. Un formateador transforma un valor *esto es, un Object+ a una tira de caracteres usando el m(todo valueToString(Object y una tira de caracteres a un valor *esto es, un Object+ usando el m(todo stringToValue(String . 4stos son los m(todos que le permiten almacenar lo editado como una subclase de Object y mostrar este valor como una tira de caracteres en el campo. 6a siguiente figura muestra la &erarqu$a de clases de los distintos formateadores3

Figura 1 Jerarqu!a de formateadores

4l m)s sencillo es $efaultFormatter que se utili/a para formatear ob&etos arbitrarios. 4l m(todo valueToString( , simplemente, devuelve el resultado del m(todo toString( del valor almacenado. N para almacenar una tira como valor, usa un constructor de la clase del ob&eto que tenga como par)metro una tira de caracteres. InternationalFormatter es una subclase de $efaultFormatter que usa java.text.Format para pasar de String a Object y viceversa. 1or defecto, slo admite caracteres correctos *setAllowsInvalid(false +, por lo que no es conveniente modificar esta propiedad si no queremos tener problemas. @ de .

Tambi(n se encarga de a&ustar la posicin del cursor, situ)ndolo sobre aquellas posiciones en las que se puede escribir. 6umberFormatter es una subclase de InternationalFormatter dise-ada especialmente para la entrada de n0meros. 4ntre otras cosas, establece el comportamiento de la tecla 9menos: de manera que, estemos donde estemos del campo, convierte el n0mero entrado en negativo.@ 6a tecla 9mFs: pasa el n0mero a positivo. 4sto es, desaparece el signo menos. $ateFormatter es una subclase de InternationalFormatter dise-ada especialmente para la entrada de fechas. 2omo hemos comentado m)s arriba, define el comportamiento de las flechas del teclado para aumentar o disminuir d$as, meses, a-os, etc. 6a clase +as,Formatter e%tiende $efaultFormatter y est) pensada especialmente para la edicin de tiras de caracteres con formatos espec$ficos. 2omo hemos visto m)s arriba, se basa en una m)scara que indica qu( caracteres se pueden escribir en una posicin determinada.

8ersonali6aci/n de los .ormateadores


Todos los formateadores tienen comportamientos por defecto. 1or e&emplo, $ateFormatter no admite caracteres incorrectos en la edicin y +as,Formatter est) siempre en modo de sobrescritura. 1ero podemos cambiar alguno de estos comportamientos o acceder a alguna de sus caracter$sticas ya que nos proporcionan m(todos de acceso. 9s$, $efaultFormatter nos proporciona los siguientes m(todos31?

setAllowsInvalid(boolean 3 7os permite decidir si aceptamos caracteres incorrectos o no. set-ommitsOnValid?dit(boolean 3 7os permite, en modo de edicin, decidir cu)ndo se libra el valor de lo que estamos escribiendo al campo. Si usamos true como par)metro, cada ve/ que escribamos algo se validar) y, si es correcto, se asignar) como valor del campo. setOverwrite+ode(boolean 3 7os permite decidir si la modalidad de edicin es sobrescritura *true+ o insercin *false+. set+aximum(-omparable 3 1ara establecer el valor m)%imo admisible por el campo. set+inimum(-omparable 3 1ara establecer el valor m$nimo admisible por el campo.11 getFields(int!offset 3 1ara determinar qu( campo *entero, decimal, signo, etc.+ se corresponde con una posicin determinada.1.

InternationalFormatter nos ofrece tres posibilidades interesantes como3


@ 2uriosamente, si no hemos entrado ning0n te%to o valor y no permitimos la entrada de caracteres incorrectos, pulsar la tecla 9menos: no sirve de nada. 1? 4n los componentes que he desarrollado de e&emplo, he considerado necesario facilitar el acceso a alguno de los m(todos de personali/acin de formateadores desde el propio componente. 9s$, por e&emplo, los componentes ponen a disposicin del programador m(todos como setOverwrite+ode(boolean o setAllowInvalid-"aracters(boolean . 11 6os m(todos set+aximum(-omparable y set+inimum(-omparable se han implementado en los componentes de e&emplo $efault6umberField, IntegerField, $ecimalField. 4sto permite establecer rangos de valores aceptables para instancias de dichos componentes y de sus subclases 1ercentField y +one5Field. 1. ;(ase el m(todo sum(int!sign del componente de e&emplo $efault6umberField.

1? de .

9 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 m(todo setValue(object , no se tiene en cuenta el rango y el valor se asigna sin problemas al campo.1F +as,Formatter nos obsequia con algunos m(todos realmente 0tiles3

setInvalid-"aracters(String 3 7os permite especificar una lista de caracteres que no ser)n aceptados por el campo. Supongamos, por e&emplo, que tenemos un campo con una m)scara para entrar cdigos de producto. 6a m)scara podr$a ser parecida a (sta3 8UAAAK. 4s decir, un car)cter alfab(tico que ser) pasado a may0sculas, seguido de tres d$gitos. 4s de esperar que el usuario no entre una letra acentuada en la primera posicin de la m)scara, pero los usuarios son muy listos y seguro que m)s de uno lo intentar). Si recordamos la sinta%is para la especificacin de m)scaras, observaremos que no hay ninguna manera de especificar que no admitiremos caracteres acentuados. 1or lo tanto, el usuario astuto puede entrar una P y fastidiarnos la aplicacin. 6a manera de impedirlo es, pues, usando el m(todo setInvalid-"aracters( al que se le pasar) como par)metro una String con todos los caracteres acentuados *en may0sculas+. setValid-"aracters(String 3 7os permite especificar la lista de caracteres que ser)n aceptados. Se trata del m(todo complementario del anterior. Siguiendo con el mismo e&emplo, podr$amos especificar que los caracteres aceptables son .AO-$?F@AIJK>+6O1QRSTBVSTUV*&);<=WXY'0. set1laceAolder(String y set1laceAolder-"racter(c"ar 3 permiten, como hemos visto m)s arriba, especificar los caracteres que no se mostrar)n en las posiciones escribibles. 4n el e&emplo del campo de "7I, el car)cter utili/ado era el de subrayado. setValue-ontains>itteral-"aracters(boolean 3 7os permite decidir si los valores entrados, con setValue( , o recuperados, con getValue( , contienen tambi(n los literales incluidos en la m)scara *true+ o no *false+. 9s$, si nuestra m)scara para "7I es 8AA.AAA.AAADUK y hemos especificado true, getValue( , nos devolver) &).;<=.WXY(A. Si, por el contrario, especificamos false, nos devolver) &);<=WXYA. "e igual manera, si hemos especificado true, el par)metro para setValue( tendr) que ser .&).;<=.WXY(A0 y si hemos especificado false, .&);<=WXYA0.

Asi2naci/n de .ormatos
6a 0nica manera que tenemos de asignar formatos a un JFormattedTextField es mediante una subclase de JformattedTextField.AbstractFormatterFactor5. 7ormalmente, pues, usaremos la 0nica e%istente3 $efaultFormatterFactor5. $efaultFormatterFactor5 permite especificar cuatro AbstractFormatters para tres situaciones distintas3 1. ,ormato por defecto3 Se usa si no hay otro definido para una situacin concreta, lo cual implica que se usar) tanto como formato de edicin como de visuali/acin y como nulo, si
1F 4sto es debido a las diferencias de comportamiento entre setValue( y commit?dit( que se comentan m)s aba&o. 4ste comportamiento ha sido 8corregidoK en los componentes num(ricos de e&emplo. Si se intenta asignar un valor fuera de rango, se lan/a una IllegalArgument?xception.

11 de .

slo especificamos (ste. .. ,ormato de edicin3 Se usa cuando el campo tiene el foco y sirve para facilitar la edicin F. ,ormato de visuali/acin3 Se usa cuando el campo no tiene el foco y se utili/a para mostrar el valor . ,ormato nulo3 Se usa cuando el campo tiene un valor nulo *null+

(os -rocesos
4n el apartado "#ser$aciones generales, he presentado un breve esquema de los principales procesos que reali/a JFormattedTextField para almacenar un valor y mostrarlo. ;amos ahora a entrar con un poco m)s de detalle en estos procesos.

Asi2naci/n del valor


Gientras estamos escribiendo, JFormattedTextField no asume, en principio, ning0n valor. 6o que escribimos est), por as$ decirlo, en el aire y slo se puede obtener con el m(todo getText( com0n a todos los Jtext-omponents. 6a e%cepcin a dicho comportamiento est) en el hecho de especificar set-ommitsOnValid?dit(true para el formateador correspondiente, como hemos comentado m)s arriba. Hay dos maneras de asignar un valor al campo3 de manera autom)tica y por programa.

Asi2naci/n de valor a+tom0tica


2uando pulsamos 9intro: o cuando cambiamos el foco, empie/a el proceso de asignacin autom)tica de valor. 9 grandes rasgos, lo que sucede al pulsar 9intro: o cambiar el foco es lo siguiente3 1. 4&ecuta el m(todo commit?dit( . 4ste mira si hay un AbstractFormatter definido que se encargue de transformar el te%to en un ob&eto. Si no lo encuentra, no asigna valor. 4s decir, si usamos el m(todo getValue( de JFormattedTextField, nos devolver) null. .. Si encuentra el AbstractFormatter, obtendr) el te%to entrado mediante getText( ! y usar) el m(todo stringToValue( para obtener el ob&eto correspondiente y asignarlo. 4l proceso de transformacin de una tira a un ob&eto, comporta un an)lisis de la tira y es posible que no funcione. 4n este caso, el AbstractFormatter generar) una 1arse?xception y no se asignar) ning0n valor. Un e&emplo t$pico ser$a el intento de asignacin de la tira &OOO *obs(rvese que en ve/ de ceros hay os may0sculas+ mediante un 6umberFormatter. Oste intentar) convertir esta tira en un >ong y se producir) una e%cepcin. 4l resultado es que getValue( nos devolver) null o el 0ltimo valor correcto entrado. 1ero JFormattedTextField nos permite afinar un poco m)s en el caso de la asignacin de valor por cambio de foco y nos permite establecer pol$ticas a seguir. 1ara ello usaremos el m(todo JFormattedTextField.setFocus>ostOe"avior(int!be"avior . 6a siguiente tabla las resume3

1. de .

9alor JFormattedTextField.R?V?RT

Descri-ci/n
<evierte lo editado al 0ltimo valor almacenado en el campo. 4s decir, al valor devuelto por el m(todo getValue( . Si no hay ning0n valor almacenado previamente o no for/amos un setValue( , por e&emplo, pulsando 9intro:, el contenido de la edicin actual se perder). 4ntrega el valor actual al perder el foco. Si el valor editado no es considerado un valor legal por el AbstractFormatter *esto es, se lan/a una 1arse?xception+, entonces el valor editado no cambiar) pero no se asignar) como valor. <esumiendo, se comporta como -O++IT, pero si el valor editado no es correcto, no limpia el campo.

JFormattedTextField.-O++IT

JFormattedTextField.-O++IT3OR3R?V?RT 4s similar a -O++IT, pero si el valor que escribimos no es legal *esto es, el AbstractFormatter lan/a una 1arse?xception+, se comporta como R?V?RT y limpia el contenido del campo. JFormattedTextField.1?RSIST 7o hace nada, no obtiene un nuevo AbstractFormatter y no actuali/a el valor. Sea correcto o incorrecto lo que entremos, mantiene el valor correcto anterior pero no limpia el campo.

Ta#la 1 %ol!ticas de asignaci&n de $alor en la p'rdida de foco

6a pol$tica por defecto es -O++IT3OR3R?V?RT.1

Asi2naci/n de valor -or -ro2rama


9 grandes rasgos, el proceso de asignacin funciona de manera similar a la asignacin autom)tica. "isponemos de dos m(todos para asignar un valor3 setValue(Object!valor y commit?dit( , descrito m)s arriba. 4l m)s m)s usado es setValue(Object . 4l proceso, resumido, es el siguiente3 1. Gira si dispone de un formateador *en este caso, mira si hay definida una FormatterFactor5+. .. Si no hay ninguna definida, la crea bas)ndose en la clase del ob&eto pasado como par)metro. 4ste ob&eto debe ser una instancia de $ateFormat, 6umberFormat, Format, $ate o 6umber. JFormattedTextField crear) una $efaultFormatterFactor5 basada en el tipo del valor que intentamos asignar. Si se trata de una instancia de $ateFormat,
1 6a aplicacin de e&emplo IntegerFieldTest permite hacer pruebas con las distintas pol$ticas de p(rdida de foco y con el m(todo set-ommitsOnValid?dit(boolean .

1F de .

crear) una $efaultFormatterFactor5 basada en un $ateFormatter, si es una instancia de 6umberFormat, usar) un 6umberFormatter, si es una $ate, usar) $ateFormatter, si es un Format, usar) InternationalFormatter, si se trata de un 6umber, usar) un 6umberFormatter como formateador por defecto y para visuali/acin y un 6umberFormatter especial que usa un $ecimalFormat con el patrn ././0 para la edicin. F. 9signa el valor. Pbservamos una diferencia notable entre commit?dit( y setValue( . 4l primero usa el m(todo stringToValue( para obtener el valor a pasar como par)metro de setValue( , mientras que (ste asigna el valor directamente. 4sto es, commit?dit( puede recibir una 1arse?xception como resultado de invocar stringToValue( si el formateador detecta un error de formato. Hemos de hablar, pues, de un comportamiento asim(trico entre commit?dit( y setValue( ! que no suele tener consecuencias. Sin embargo, hay alg0n caso en que esta asimetr$a comporta alg0n que otro problema. ;eamos un e&emplo3 7osotros construimos un campo para entrada de "7Is con un +as,Formatter, tal y como hemos visto m)s arriba. 1ero ahora decidimos que el valor del campo no debe contener literales y lo especificamos usando el m(todo value-ontains>itteral-"aracters(false . Si asignamos como valor, por e&emplo, .&).;<=.WXY(V0, usando setValue( , no se produce ning0n error ya que no interviene para nada el formateador. 4s m)s, getValue( devuelve .&).;<=.WXY(V0 en ve/ de .&);<=WXYV0.1J

1J 4sta asimetr$a ha sido corregida para el componente de e&emplo $6IField. 4l m(todo setValue( llama siempre al formateador para comprobar errores de formato.

1 de .

A8(I4A4IONES DE EJE38(O
1ara ilustrar los conceptos tratados en este art$culo, he desarrollado una serie de aplicaciones. "ichas aplicaciones se incluyen con el cdigo fuente correspondiente para que el lector pueda estudiarlas y modificarlas a su conveniencia. He procurado que los e&emplos no sean abstractos sino que sean pr)cticos y usables para cualquier desarrollador. He clasificado los e&emplos en tres categor$as3 1. 4om-onentes a+xiliares1 se usan en las aplicaciones de demostracin y tienen poco que ver con JFormattedTextField. 9 pesar de ello, creo que algunas de ellas pueden ser bastante interesantes para los desarrolladores. .. 4om-onentes derivados de JFormattedTextField1 son un con&unto de subclases de JFormattedTextField que, a mi entender, cumplen un doble ob&etivo. 1or una parte ilustran la mayor parte de conceptos relacionados con JFormattedTextField y con los distintos formateadores y por otra, constituyen un con&unto de componentes *en ingl(s, los llamar$an widgets+ especiali/ados en distintas tareas *entrada de n0meros, porcenta&es, fechas y "7Is+ listos para ser utili/ados por cualquier desarrollador. 6a estrategia seguida para el desarrollo de los componentes ha sido doble. 1or una parte, he a-adido funcionalidades que no est)n directamente relacionadas con !,ormattedTe%t,ield, como la aritm(tica de fechas, la asignacin de escala a un valor decimal o la autocomplecin de un "7I y, por otro, he hecho emerger, a nivel de componente, propiedades del formateador, como la asignacin din)mica del formato de representacin de fechas o la especificacin de rango para los campos num(ricos. F. A-licaciones de demostraci/n1 se trata de peque-as 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. 9 continuacin, paso a describir brevemente cada una de ellas.

4om-onentes a+xiliares
4IF:NIF
4s una clase que proporciona una serie de m(todos est)ticos para la verificacin de 2I,s y 7I,s espa-oles. 2ontiene una amplia documentacin sobre las fuentes en las que me he basado para escribirla y la casu$stica que se trata. "estacar$a las siguientes funcionalidades3

"etermina si una tira se corresponde con un 7I, o con un 2I, "etermina si un 7I, o un 2I, son correctos "ado un 7I, sin letra de control, calcula y devuelve dicha letra Trata 7I4s *7I,s para e%tran&eros+

4sta clase se utili/a en el componente $6IField.

;o+ndJS-inner
4s una subclase de JSpinner que tiene la propiedad value #ound. 4sto es, cada ve/ que el valor 1J de .

de OoundJSpinner cambia, se genera un 1ropert5-"ange?vent. Se usa en las demostraciones de algunos de los componentes.

;+tton'ro+-J8anel
4s una subclase de J1anel que facilita el uso de JRadioOutons desde un editor visual. Si queremos un comportamiento normal de mutua e%clusin de JRadioOutons *esto es, que cuando se pulse en uno el que estaba seleccionado de&e de estarlo+, es necesario a-adir todos los JRadioOutons a un Outton@roup. Outton@roup1anel, se encarga de ello por nosotros. Outton@roup1anel est) basado en un e&emplo de Scott Stanchfield *http3::www.&avadude.com+ y se usa en las demostraciones de algunos componentes.

Over<rite4aret
4s una subclase de $efault-aret que dibu&a un cursor hori/ontal. Se utili/a para indicar que estamos en modalidad de sobrescritura.

8air
Un simple #ean no visual que mantiene una pare&a de tipo clave:descripcin. Se usa en los J-ombobox de algunas de las demostraciones de los componentes.

4om-onentes derivados de JFormattedTextField


Son componentes de e&emplo, usables,1L que llevan a la pr)ctica todo lo que he intentado e%plicar sobre JFormattedTextField y su entorno. <ecomiendo vivamente al lector que estudie con cari-o el cdigo fuente y lea los ja$adocs de las distintas clases. 2reo que esto va a ser m)s pr)ctico *y m)s corto+ que entrar en los detalles de dise-o de cada una de los componentes.

En=ancedJFormattedTextField
4s una interface que establece los m(todos, y por ende las funcionalidades, generales del con&unto de componentes.

De.a+ltJFormattedTextField
4s una subclase abstracta de JFormattedTextField que implementa la interface ?n"ancedJFormattedTextField y que contiene cdigo para funcionalidades comunes al resto de los componentes. "estaco las siguientes3

Qestin y creacin de la AbstractFormatterFactor5 usada por los distintos subcomponentes. 1osibilidad de establecer la modalidad de escritura y mostrar un cursor diferente para cada modalidad. 6a asignacin de dicha funcionalidad a la tecla 9ins:, que intercambia las dos modalidades de escritura.

1L 9 pesar de haber reali/ado una infinitud de pruebas y de dise-ar y e&ecutar pruebas unitarias, puede que los componentes no se comporten como debieran. 6os proporciono a guisa de e&emplos y no me responsabili/o de los efectos colaterales que se deriven de su uso en produccin.

1L de .

Implementa el m(todo clear( que permite borrar el contenido de un campo. Hace accesibles, a nivel de componente, el uso de los m(todos set-ommitsOnValid?dit(boolean y get-ommitsOnValid?dit( de $efaultFormatter. Implementa, a nivel de componente, la pol$tica de aceptacin de caracteres incorrectos del formateador. Implementa, a nivel de componente, la pol$tica de establecimiento y gestin de rangos de valores aceptables. Implementa el m(todo is?mpt5( que nos indica si el campo est) vac$o..

De.a+ltN+mberField
4s una subclase abstracta de $efaultJFormattedTextField que contiene cdigo para las funcionalidades comunes de los campos num(ricos *$ecimalField, IntegerField, +one5Field y 1ercentField+. 1or e&emplo, 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 num(ricos.

DecimalField
4%tiende $efault6umberField adapt)ndolo a la presentacin y edicin de n0meros decimales. "estacar( las siguientes funcionalidades3

"istingue el modo de presentacin, en el que muestra separadores de millares y un car)cter de separacin decimal acorde con el >ocale, del de edicin, en el que se facilita el uso del teclado num(rico 1ermite establecer diversas pol$ticas de redondeo 1ermite determinar la escala 6os valores entrados se almacenan siempre como Oig$ecimals Se le puede asignar cualquier valor derivado de 6umber, pero tambi(n valores de tipos nativos *int, long, b5te, s"ort, float, double, etc.+. Internamente, se almacenan como Oig$ecimals

Inte2erField
4s una subclase de $efault6umberField que facilita la edicin y presentacin de n0meros enteros. Se le puede asignar cualquier valor derivado de 6umber *si el valor tiene decimales, slo se toma la parte entera+ pero tambi(n valores de tipos nativos *int, long, b5te, s"ort, float, double, etc.+. Internamente, se almacenan como OigInteger.

3one5Field
4%tiende $ecimalField asignando como formato de visuali/acin el de moneda.

8ercentField
4%tiende $ecimalField asignando como formato de visuali/acin el de porcenta&e. 1M de .

DNIField
4s una subclase de $efaultJFormattedTextField que facilita la entrada y validacin de "7Is espa-oles mediante una m)scara de entrada. ,uncionalidades destacables3

1ermite determinar si el "7I entrado es correcto *boolean!$6IField.isOK( + 1ermite la activacin y desactivacin del proceso de verificacin. Si est) activada la verificacin y el valor entrado no es correcto, se deshabilita el cambio de foco. 1ermite completar el "7I con la letra de control correcta pulsando 9-trl(?spacio: o, tambi(n, cuando el campo pierde el foco. 4vita la entrada de letras de control no admisibles para "7Is.

DateField
4s una subclase de $efaultFormattedTextField que facilita la entrada, visuali/acin y mane&o de fechas y horas. "estaco las siguientes funcionalidades3

9dmite valores asignables de tipo $ate y -alendar 1ermite cambiar din)micamente el formato de visuali/acin *el de edicin es el mismo que el de visuali/acin+ especificando patrones con sinta%is de Simple$ateFormat Implementa una aritm(tica simple de fechas. 1ermite a-adir o quitar d$as, semanas, meses, a-os, horas, minutos o segundos a la fecha almacenada como valor en el campo de manera sencilla *p.e. add+ont"s(; , a-adir$a tres meses, addSee,s((; restar$a tres semanas a la fecha+.

Strin2Field
4%tiende $efaultFormattedTextField para facilitar la escritura de te%to. Si bien (wing nos proporciona ya un campo de te%to, JTextField, considero que no es suficiente para cubir algunas de las necesidades m)s importantes de un campo de este estilo. 9s$, por e&emplo, JTextField slo nos proporciona un m(todo de escritura, la insercin, y no nos permite determinar la longitud m)%ima del te%to a escribir. 4ste segundo aspecto es importante si tenemos ligado el te%to a alguna columna de una tabla en una base de datos. Si usamos JTextField, no podemos asegurar que el te%to 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 m)%ima admisible para el te%to. StringField nos permite, tambi(n, establecer una pol$tica de recorte para la asignacin de valor. Si la activamos, usando el m(todo 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, lan/ar) una IllegalArgument?xception al intentar asignar un valor con una longitud superior a la permitida.

1> de .

A-licaciones de demostraci/n
Siempre se ha dicho que una imagen *en nuestro caso, una aplicacin visual+ vale m)s que mil palabras. 4s por este motivo que he creado una serie de aplicaciones de escritorio que pretenden e&emplificar las funcionalidades de cada uno de los componentes comentados en el apartado anterior. 9s$, pues, el lector dispone de un e&emplo de uso para cada uno de los componentes derivados de JFormattedTextField3

!! $ecimalFieldTest H Ilustra las posibilidades de $ecimalField IntegerFieldTest !! !! H Ilustra las posibilidades de IntegerField y las distintas pol$ticas de comportamiento de JFormattedTextField con la p(rdida de foco. Tambi(n muestra las posibilidades de uso de setAllowsInvalid( . 1ermite, a su ve/, verificar las asignaciones de valor cuando hay p(rdida de foco en funcin de la pol$tica definida. !! e5FieldTest +on !! H Ilustra las posibilidades de +one5Field !! centFieldTest 1er !! H Ilustra las posibilidades de 1ercentField !! $6IFieldTest H Ilustra las posibilidades de $6IField !! $ateFieldTest H Ilustra las posibilidades de $ateField !! ingFieldTest Str !! H Ilustra las posibilidades de StringField

4stas aplicaciones se pueden e&ecutar por separado o bien a trav(s de la clase 1ruebas que nos permite decidir qu( aplicacin e&ecutar. 6os e&emplos de uso son, creo, bastante intuitivos, sin embargo, hay algunos trucos poco evidentes3

4n la aplicacin $6IFieldTest, no hace falta escribir siempre la letra del "7I, si se han entrado todos los n0meros del "7I, basta con pulsar -trl(?spacio y la letra correcta aparecer) por arte de magia. Si lo que sucede es que la letra entrada es incorrecta, tambi(n se puede recurrir a -trl(?spacio para que se cambie por la correcta. 4n la aplicacin $ateFieldTest, despu(s de especificar un nuevo patrn, podemos activarlo pulsando el botn OK o bien pulsando intro en el campo de patrn. Tambi(n es importante tener en cuenta que en el campo AZadir, podemos especificar cantidades negativas para que reste. 4n los e&emplos IntegerFieldTest y $6IFieldTest, la combinacin de teclas 9ctrl(v:, cuando el foco est) en el campo, abren un di)logo que muestra el valor del campo.

1@ de .

Ar>+itect+ra de clases
6a siguiente figura nos muestra el diagrama de clases de los componentes de e&emplo derivados de JformattedTextField. T(ngase en cuenta que el diagrama no incluye todos los m(todos.

Figura ) *iagrama de clases de los componentes de ejemplo

.? de .

.1 de .

E8?(O'O
4s notable el aparente cambio de estrategia de Sun proporcionando en la versin 1. de !ava dos nuevos componentes (wing que intentan cubrir vac$os importantes en lo que al desarrollo de interficies gr)ficas se refiere. 6amentablemente, la versin J.? no incluye ning0n componente nuevo ni me&ora los anteriores. JFormattedTextField nos permite desarrollar aplicaciones m)s profesionales y me&ora la imagen de (wing. Tenemos m)scaras, campos de fecha con un comportamiento ra/onable, podemos usar diversos formateadores para personali/ar nuestros campos, etc. Sin embargo, durante el tiempo que me ha llevado construir este art$culo, he encontrado algunos obst)culos que me han dificultado la labor de escribir tanto el te%to del art$culo como los componentes de e&emplo. He encontrado, y es una opinin personal, problemas de ortogonalidad, algunos de los cuales ya he e%puesto, como la diferencia de comportamiento de commit?dit( y setValue( que, combinados con la admisin o no de literales en el valor del +as,Formatter, me han dado alg0n que otro quebradero de cabe/a. 4n el mismo orden de cosas estar$a el establecimiento de rangos de InternationalFormatter. Siguiendo con la ortogonalidad, me pregunto Rdnde est) el model de JformattedTextFieldB 2iertamente, sigue siendo el mismo que el de su padre, JTextField, un 1lain$ocument. Sin embargo, las relaciones entre vista:controlador *delegate+ y modelo, ni son tan claras como en JTextField ni se cuentan en parte alguna. Ge he encontrado tambi(n con problemas de visibilidad *scope+ cuando he intentado e%tender, por e&emplo, $efaultFormatter. Hay m(todos importantes de $efaultFormatter y de JText-omponent que slo est)n visibles a nivel de package y que dificultan e%tender tanto $efaultFormatter como AbstractFormatter. 4s realmente comple&o e%tender los formateadores que nos vienen dados. 4n el proceso de creacin de este art$culo, me propuse reproducir un componente que hab$a desarrollado hace tiempo como una e%tensin de JTextField y que ofrec$a una funcionalidad sencilla pero pr)ctica3 determinar el n0mero m)%imo de caracteres que pod$a aceptar un campo de entrada. 9nte la dificultad de e%tender $efaultFormatter, decid$ ir directamente a 1lain$ocument! y atacar el modelo como hice anteriormente. =ien, no acab de funcionar. 4l m(todo insertString( de Abstract$ocument no se invoca al insertar una tira *por teclado o desde el clip#oard+ como en JTextField, sino cuando el campo cambia de foco. 6a falta de tiempo y las dificultades han hecho que abandonara esta l$nea. ,inalmente, y para la versin 1.1 de este art$culo, he desarrollado StringField, pero recurriendo al control de la propiedad value, ya que las otras v$as, a mi entender m)s coherentes, han resultado imposibles de seguir *posiblemente por mis limitaciones personales+. 9 pesar de los pesares, creo que JFormattedTextField es un componente importante que debe formar parte, de manera habitual, en nuestras aplicaciones. "eseo que el lector pueda, con la ayuda de este art$culo, sortear me&or que yo las dificultades de creacin de componentes derivados de JFormattedTextField y que este art$culo contribuya a hacer un me&or y mayor uso de (wing en sus aplicaciones de escritorio.

.. de .

)*U@ AE USADO,
He usado 4clipse F.?.1 *http3::www.eclipse.org+ para el desarrollo, la generacin de !avadocs y las pruebas unitarias con !Unit F.>.1 *http3::www.&unit.org+. 1ara el desarrollo de las interficies de usuario en Swing, he usado el ;isual 4ditor de 4clipse *http3::www.eclipse.org:vep:+ en su versin 1.?...1<2.. 1ara la generacin del diagrama de clases de los componentes, he usado la 0ltima versin del plugin de 4clipse Pmondo 4clipseUG6 *http3::www.omondo.com:inde%.html+. 4ste art$culo ha sido escrito con PpenPffice ..? beta *http3::www.openoffice.org:+ y (ste tambi(n se ha usado para la generacin del 1",.

)*U@ AE (E?DO,
<ealmente, hay poca literatura que haga referencia a JformattedTextField. No slo he encontrado un par de tutoriales que cubren los aspectos m)s b)sicos. 4l primero, siempre es una referencia, es el cap$tulo +ow to Use Formatted Text Fields *http3::&ava.sun.com:docs:booSs:tutorial:uiswing:components:formattedte%tfield.html+ del tutorial oficial de !ava. 4s correcto, pero creo que insuficiente si quieres traba&ar a fondo con las posibilidades de JformattedTextField. 4%pone con claridad algunos conceptos b)sicos. 4l segundo, es el art$culo de !ohn TuSowsSi SwingEs new !,ormattedTe%t,ield component *http3::wwwD1?L.ibm.com:developerworSs:&ava:library:&Dmer?L.J:+ de &unio de .??. dentro de la interesante serie de art$culos sobre novedades de la versin 1. de !ava Gagic with Gerlin que el autor ha publicado en developer'orSs. =ien escrito pero muy b)sico. 2omo he comentado m)s arriba, para entender el funcionamiento de JFormattedTextField, he tenido que leer mucha 91I y bastante cdigo fuente.

INSTA(A4I7NB 4ONTENIDO C EJE4U4I7N


4ste tutorial y los archivos relacionados est)n empaquetados en un archivo TI1. 9l descomprimirlo *respetando la estructura de directorios+ se crear) el subdirectorio JFTF que contiene3

4l archivo >??+?.TTT que e%plica, como aqu$, qu( contiene el directorio y cmo se usa. 4ste art$culo en formato 1",. 4l archivo jftf.jar que contiene los componentes de e&emplo, las aplicaciones de demostracin y los tests unitarios. 4l subdirectorio src que contiene el cdigo fuente. 4l subdirectorio bin con las classes compiladas. 4l subdirectorio doc que contiene los &avadoc de todas las clases.

EDec+ci/n de las a-licaciones de eDem-lo


6as aplicaciones de e&emplo se pueden e&ecutarse por separado o bien, yo lo recomiendo, e&ecutando la clase com.froses.jftf.widgets.demo.1ruebas3 .F de .

java!(classpat"!jftf.jar!com.froses.jftf.widgets.demo.1ruebas

o bien
java!(jar!jftf.jar

desde el directorio [...\]JFTF creado al descomprimir el archivo TI1 del art$culo. Si el lector est) usando un entorno 'indows, puede, simplemente, hacer doble clic sobre el archivo jftf.jar.

Estr+ct+ra del c/di2o .+ente


4l cdigo est) organi/ado en cinco packages3 1. com.froses.jftf.tools3 2ontiene los componentes au%iliares -IF36IF y 1air. .. com.froses.jftf.widgets3 2ontiene los componentes de e&emplo derivados de JFormattedTextField. F. com.froses.jftf.widgets.demo3 2ontiene las aplicaciones de demostracin. . com.froses.jftf.widgets.tools3 2ontiene los componentes au%iliares gr)ficos3

OoundJSpinner Outton@roupJ1anel Overwrite-aret

. de .

También podría gustarte