Documentos de Académico
Documentos de Profesional
Documentos de Cultura
J Formatted Text Field
J Formatted Text Field
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.
)*+ 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
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 .???.
,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
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 %
"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 .
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 .
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.
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 .
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
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.
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.
@ 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.
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.
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+
;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.
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.
.? 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.
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.
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.
. de .