You are on page 1of 24

USOS INTERESANTES DE JFormattedTextField

v. 1.1 Francesc Ross i Albiol (03/2005)


Todos los que en alguna ocasin nos hemos tenido que enfrentar al desarrollo de interficies de usuario en Swing nos hemos encontrado con algunas deficiencias en cuanto a los componentes disponibles. Una de ellas, y creo que importante por su uso masivo en aplicaciones de este tipo, ha sido la de los campos de entrada. Hasta la aparicin de la versin 1.4 del JDK, slo disponamos de JTextField. Un componente bastante limitado que pona de manifiesto las deficiencias de Swing respecto a otras aproximaciones como, por ejemplo, Delphi. Siempre he defendido a Swing respecto a las tpicas aproximaciones de Windows haciendo hincapi en la bondad de su arquitectura y las posibilidades que sta ofrece al desarrollador para extender de manera relativamente fcil (o, al menos, ortogonal) los componentes que nos ofrece. Fruto de ello fue la pequea coleccin de widgets que desarroll para JDK 1.2 que inclua, entre otros, un campo con mscara o campos especializados para nmeros.1 Pero la verdad es que, a pesar de dichas posibilidades de expansin, si queras algo tan simple como un spinner, te lo tenas que fabricar y eso siempre da pereza y est sujeto a errores difciles de controlar. Cuando apareci la versin 1.4 del JDK, tuve la impresin de que Sun haba, de alguna manera, recogido las quejas de los usuarios y se haba decidido a cubrir algunas de las necesidades bsicas del desarrollador de interficies de usuario proporcionando, por primera vez en bastante tiempo, dos componentes bsicos: JSpinner y JFormattedTextField. Este artculo, como su ttulo indica, pretende profundizar en las posibilidades que nos ofrece JFormattedTextField. JFormattedTextField no es ms que una extensin de JTextField que viene a cubrir algunas de las deficiencias que todos encontrbamos en l. Un campo de entrada es un componente que cumple una doble funcin. Por una parte, permite que el usuario entre el texto que se corresponde con un dato solicitado por la aplicacin; y por otra, permite a la aplicacin mostrar datos al usuario. La principal limitacin que le encuentro a JTextField es que permite entrar cualquier texto y que no hay manera fcil de mostrar un texto con un formato concreto. No hay posibilidad de establecer un control sobre lo que el usuario entra ni manera sencilla de mostrar convenientemente datos de tipos tan habituales como fechas o nmeros. Lo primero que uno piensa cuando se acerca por primera vez a JFormattedTextField es finalmente tenemos un campo que soporta mscaras. Todos esperbamos este componente. Sin embargo, su nombre no es algo as como JMaskedTextField. Su nombre nos insina que va ms all de un campo con mscaras. Se trata de un campo de entrada de texto que nos permite especificar formatos. Ciertamente, una manera de especificar un formato de entrada es mediante una mscara, pero no es el nico. Adems, como acabo de comentar, un campo de entrada no slo sirve para
1 Algunos de estos widgets se pueden encontrar en mi Web personal (http://www.froses.com/ES/Descarregues/Widgets.htm).

1 de 24

entrar texto. Tambin muestra lo que hemos entrado. Volveremos ms tarde sobre este punto. Resumiendo un poco las caractersticas de este componente podemos decir que: Distingue entre el valor del campo y el texto que lo representa Permite especificar formatos fijos de entrada de datos, por ejemplo, mediante mscaras Sabe aprovechar el resto de especificaciones de formato disponibles en Java para nmeros, fechas, horas, etc. Permite decidir si se admiten caracteres incorrectos en la entrada o no. Permite distinguir entre modalidad de edicin y modalidad de visualizacin. Permite establecer dos modalidades de escritura: insercin y sobrescritura. Permite que decidamos qu hacer con el foco si lo que el usuario ha entrado no es correcto, al beneficiarse de las nuevas capacidades del JDK 1.4 para la comprobacin de valores en Swing. Bueno, creo que las posibilidades que nos ofrece JFormattedTextField son esperanzadoras e intentar mostrar hasta qu punto. Para ello, he pensado dividir el artculo en tres partes diferenciadas con objetivos distintos. La primera, muestra los usos ms habituales de JFormattedTextField y comenta cmo usar la clase javax.swing.InputVerifier para controlar el foco en base al valor entrado en el campo. El objetivo, en esta primera parte, es conseguir que el lector pueda utilizar fcilmente JFormattedTextField en sus aplicaciones. La segunda discute ms a fondo la arquitectura y el funcionamiento de JFormattedTextField, y tiene como objetivo preparar al lector para poder extender las posibilidades de JFormattedTextField, extendindolo y creando nuevos componentes especializados. En la tercera, presento algunos widgets derivados de JFormattedTextField, y desarrollados especficamente para este artculo, que tienen un doble objetivo: mostrar al lector una posible va de expansin del componente que nos ocupa y proporcionarle unos componentes listos para ser usados en sus aplicaciones. Tambin proporciono algunas aplicaciones que ejemplifican tanto el uso de estos widgets como de algunos aspectos de JFormattedTexField y de las clases derivadas de JFormattedTextField.AbstractFormatter.

USOS GENERALES DE JFormattedTextField


Como he comentado ms arriba, el objetivo de este captulo es proporcionar la informacin suficiente al lector para que pueda hacer uso de las principales funcionalidades de JFormattedTextField.

Qu es JFormattedTextField?
JFormattedTextField es un componente derivado de JTextField que, como ste, sirve para entrar y mostrar datos. Una de las caractersticas principales de JFormattedTextField es la de permitir dar formato a los datos, tanto en el momento de entrarlos como en el de visualizarlos. Para ello, y a diferencia de JTextField, JFormattedTextField distingue entre el valor almacenado (una subclase de Object accesible mediante el mtodo getValue()) y el texto que muestra (una java.lang.String accesible mediante getText()). En el siguiente apartado, veremos cmo podemos especificar los distintos formatos.

2 de 24

Especificacin de formato
El componente JFormattedTextField nos permite especificar el formato de diversas maneras:

De manera automtica: Asignando un valor al campo


Simplemente asignando un valor al campo, ste nos asigna un formato. As, por ejemplo, si le asignamos una fecha, l nos la permitir editar. El siguiente cdigo crea un campo de entrada para fechas con el formato por defecto:
JFormattedTextField efFecha = new JFormattedTextField(new Date());

El campo mostrar la fecha actual con el siguiente formato:


19-ago-2002

Pero no slo nos presenta la fecha. Nos permite editarla de una manera sencilla y sin error posible. Si colocamos, por ejemplo, el cursor sobre el mes y pulsamos la flecha hacia arriba, el mes cambia y pasa a ser sept. Si pulsamos la flecha hacia abajo, el mes ser jul. El mismo comportamiento se da para el da y el ao. Adems, el comportamiento es inteligente. Supongamos que la fecha sea 28 de febrero de 2002 y que aumentemos el da. La nueva fecha sera 1 de marzo de 2002. Lgicamente, si el ao fuera el 2000 (bisiesto) la fecha propuesta sera el 29 de febrero de 2000.

Mediante una mscara


Podemos utilizar una mscara para determinar el formato. Por ejemplo, si quisiramos crear un campo para entrar cdigos de cuenta corriente, podramos hacerlo as de fcil:
MaskFormatter mfCC = new MaskFormatter(####-####-##-##########); mfCC.setPlaceholderCharacter('_'); JFormattedTextField efCC = new JformattedTextField(mfCC);

El campo tendra el siguiente aspecto:


____-____-__-__________

Fijmonos que las partes escribibles se representan con el carcter de subrayado que hemos especificado con setPlaceholderCharacter(). La siguiente tabla resume los caracteres utilizables en una mscara:

Carcter
# ? A * U L H ' Un nmero Una letra

Descripcin

Una letra o un nmero Cualquier cosa Una letra que ser pasada a mayscula Una letra que ser pasada a minscula Un dgito hexadecimal (A-F, a-f, 0-9) Carcter de escape para otro carcter de mscara

Mediante descriptores de formato ya existentes


Java nos ofrece una amplia gama de especificaciones de formato para fechas, horas, nmeros y monedas. Todos ellos pueden ser utilizados, directa o indirectamente, para especificar el formato 3 de 24

usado por el campo. Ejemplificaremos algunos de ellos. Ms arriba, hemos mostrado cmo especificar un formato de fecha simplemente pasando una al constructor del campo. El resultado es vistoso, pero cualquier persona que entre datos nos dir que es poco prctico. Sera ms interesante algo del estilo de dd/mm/aa. El siguiente cdigo nos muestra cmo hacerlo:2
JFormattedTextField efFecha = new JFormattedTextField(new SimpleDateFormat(dd/MM/yy));

El resultado obtenido sera: 19/08/02. El comportamiento de las flechas sera el ya descrito. Si lo que pretendemos es entrar un nmero con un mximo de dos decimales:
JFormattedTextField efNum = new JformattedTextField(new DecimalFormat(#,###.00));

Si nos interesa que el usuario entre importes en euros en nuestro campo:


JFormattedTextField efMon = new JformattedTextField(NumberFormat.getCurrencyInstance()); efMon.setValue(new Integer(1000));

Lo que veramos sera:


1.000,00

Admitir o no caracteres incorrectos


A veces, nos puede interesar permitir que el usuario pueda entrar caracteres incorrectos. Para hacerlo, usaremos formateadores propios de JFormattedTextField. Veamos el siguiente ejemplo:3
JFormattedTextField efNum = new JformattedTextField(new DecimalFormat(#,###.00)); NumberFormatter nf = (NumberFormatter)efNum.getFormatter(); nf.setAllowsInvalid(true);

Disponemos de tres formateadores especiales derivados todos ellos de la clase javax.swing.JFormattedTextField.AbstractFormatter: MaskFormatter Utilizado para mscaras y derivado directamente de AbstractFormatter. NumberFormatter Utilizado para nmeros y derivado de una subclase de AbstractFormatter: InternationalFormatter. DateFormatter Utilizado para fechas y horas y derivado, como el anterior, de InternationalFormatter.

Insertar o sobrescribir
Algo de sumo inters es poder especificar si insertamos o sobrescribimos caracteres. Lo ideal sera que se pudiera decidir pulsando la tecla <Ins>, pero esto no es inmediato. El siguiente ejemplo nos indica cmo permitir la sobrescritura:4
2 Los componentes DateField, DecimalField, DecimalFieldScrollable, IntegerField, MoneyField y PercentField, comentadas ms abajo, ilustran la asignacin de diversos formatos y se incluyen en el cdigo fuente de este artculo. 3 La aplicacin de ejemplo IntegerFieldTest, comentada ms abajo, nos permite comprobar el funcionamiento de setAllowsInvalid(boolean). 4 El componente DefaultJFormattedTextField, comentado ms abajo, implementa los mtodos de insercin y sobrescritura y se incluye en el cdigo fuente de este artculo.

4 de 24

JFormattedTextField efNum = new JformattedTextField(new DecimalFormat(#,###.00)); NumberFormatter nf = (NumberFormatter)efNum.getFormatter(); nf.setOverrideMode(true);

Modalidad de edicin y de visualizacin


Imaginemos que tenemos un campo para entrar importes en euros como el que hemos descrito ms arriba. El resultado obtenido es interesante; se ve bien, con el smbolo de euro al final y los separadores de millares y la coma decimal siguiendo las directrices de nuestro pas. Pero una vez ms, un usuario que se dedique a entrar datos nos dira que es incmodo. Normalmente, se usa el teclado numrico y uno no tiene que ir a buscar la coma al teclado alfanumrico. Usa un punto para indicar la coma. Claro que si bien es prctico entrar 1234.35, queda mal cuando se visualiza. Tenemos, pues, un conflicto: lo que es prctico para la entrada de datos no es claro en la visualizacin. JFormattedTextField nos permite resolver este conflicto especificando un formato para la edicin y otro para la visualizacin. Cuando el foco est en el campo, usar el de edicin y cuando ste pierda el foco, usar el de visualizacin.5 Veamos cmo hacerlo para nuestro campo de importes en euros:
// Creamos el campo JFormattedTextField efDecimal = new JformattedTextField(); // Formato de visualizacin NumberFormat dispFormat = NumberFormat.getCurrencyInstance(); // Formato de edicin: ingls (separador decimal: el punto) NumberFormat editFormat = NumberFormat.getNumberInstance(Locale.ENGLISH); // Para la edicin, no queremos separadores de millares editFormat.setGroupingUsed(false); // Creamos los formateadores de nmeros NumberFormatter dnFormat = new NumberFormatter(dispFormat); NumberFormatter enFormat = new NumberFormatter(editFormat); // Creamos la factora de formateadores especificando los // formateadores por defecto, de visualizacin y de edicin DefaultFormatterFactory currFactory = new DefaultFormatterFactory(dnFormat, dnFormat, enFormat); // El formateador de edicin admite caracteres incorrectos enFormat.setAllowsInvalid(true); // Asignamos la factora al campo efDecimal.setFormatterFactory(currFactory);

Editamos en formato ingls (usamos el punto como separador decimal) y sin separadores de millares. Visualizamos lo que hemos entrado en el formato de moneda y numrico de nuestro pas. En este caso, el euro como smbolo de moneda, el punto como separador de millares y la coma como separador decimal, pero si el programa se ejecutara en Inglaterra, veran el smbolo de la Libra, la coma sera el separador de millares y el punto, el separador decimal.
5 Los componentes DecimalField, DecimalFieldScrollable, IntegerField, PercentField y MoneyField, comentadas ms abajo e incluidas en el cdigo fuente de este artculo, ilustran el uso de formatos distintos para la edicin y la visualizacin.

5 de 24

La siguiente imagen muestra nuestro campo en modalidad de edicin:

La siguiente imagen muestra el mismo campo en modalidad de visualizacin:

Si observamos el cdigo, veremos que opto por admitir caracteres incorrectos en edicin. El motivo es que NumberFormatter define el comportamiento de las teclas ms (+) y menos (-) haciendo que sean las responsables del cambio de signo. No escriben el signo, sino que lo cambian. Por ello, y para hacer que la escritura se parezca ms a la que solemos utilizar, he decidido permitir el uso de caracteres incorrectos en el ejemplo.

Control del foco: InputVerifier


Uno de los problemas tpicos en el desarrollo de interficies grficas para la entrada de datos es decidir qu se hace cuando el usuario que ha rellenado incorrectamente un campo quiere pasar al siguiente. En algunos casos nos puede interesar que lo pueda hacer, pero en otros no. Imaginemos que necesitamos un campo para entrar nmeros de DNI, con su letra. Este campo, en nuestra aplicacin, es clave ya que a partir de l, se obtiene el resto de la informacin. As, pues, si el nmero entrado fuera incorrecto, no debiramos permitir que el usuario saltara al campo siguiente. Anteriormente, haba que utilizar algn truco (que no viene al caso) para evitar que el foco se fuera al siguiente componente. En la versin 1.3 del JDK, se nos facilita bastante el trabajo. Podemos asignar al campo una clase que extienda InputVerifier mediante el mtodo setInputVerifier() de manera que sea esta clase la que controle si el usuario podr salir del campo (pasar el foco a otro componente) o no. Para seguir con el ejemplo del DNI, proponemos un pequeo ejemplo que ilustre el procedimiento.6 Vamos a definir una mscara que facilite la entrada de DNIs en nuestro campo:
// Definicin de la mscara de DNI MaskFormatter maskDNI = null; try { maskDNI = new MaskFormatter("##.###.###-U"); } catch (ParseException e) { // De momento, no hacemos nada } // El carcter a mostrar en las posiciones escribibles es el // subrayado. maskDNI.setPlaceholderCharacter('_');

La mscara obligar al usuario a entrar ocho dgitos y una letra que ser pasada a maysculas. Adems, mediante el mtodo setPlaceholderCharacter(), asignamos un carcter de subrayado para que sirva de pauta al usuario, indicndole las posiciones editables del campo. El carcter U que vemos en la mscara obligar al usuario a escribir la letra del DNI y pasar dicha letra a maysculas. La mscara se encargar, pues, de que el usuario escriba dgitos y letras donde corresponda, pero el valor entrado no ser entregado al campo directamente hasta que pulsemos la tecla Intro. Al
6 El componente DNIField, cuyo cdigo fuente se incluye, es un ejemplo completo de campo destinado a la entrada de DNIs.

6 de 24

cambiar de foco, el MaskFormatter no entrega el valor. Hay que decirle explcitamente que si lo editado es vlido, pase el valor al campo. Para ello, utilizaremos el mtodo setCommitsOnValidEdit(boolean).
maskDNI.setCommitsOnValidEdit(true);

Si comentamos esta lnea, veremos que al entrar un DNI incorrecto nos deja cambiar el foco debido a que el valor no se ha entregado al campo para que determine si debe permitir el cambio de foco o no. Finalmente, creamos el campo:
JFormattedTextField efDNI = new JformattedTextField(maskDNI);

En este momento, ya hemos dotado a nuestro campo de un cierto control para entrar DNIs:

Nos fuerza a escribir los nmeros y la letra en los lugares que corresponde Pasa automticamente la letra final de control a maysculas

Sin embargo, la mscara no nos proporciona todo el control que necesitamos. Si la persona que entra los datos se equivoca en la letra de control, el error queda registrado. Necesitamos, pues, impedir que la persona que entra los datos entre un DNI errneo (aunque, y de eso se encarga la mscara, bien formado). La versin 1.3 del JDK incorpora un nuevo mtodo a la clase javax.swing.JComponent: setInputVerifier(InputVerifier v). Este mtodo nos permite asignar a un JFormattedTextField un algoritmo de control del contenido entrado. Este algoritmo de control se hallar embebido en una subclase de InputVerifier. La clase InputVerifier es abstracta y obliga a sus subclases a implementar el mtodo public boolean verify(JComponent input). Este mtodo devuelve true, si la comprobacin es correcta, o false, si no lo es. Veamos ahora la clase derivada de InputVerifier que se encarga de verificar si el DNI entrado es correcto y permite al campo decidir si autoriza, o no, el cambio de foco. Disponemos de la clase CIF_NIF, con el mtodo esttico boolean isNIFOK(String DNI) que nos devuelve true o false en funcin del DNI pasado como parmetro.7 Creamos, por ejemplo, la clase ValidateDNI que extiende InputVerifier:
class ValidateDNI extends InputVerifier { /** * Sobrescribimos el mtodo del padre para realizar la * comprobacin del DNI entrado. */ public boolean verify(JComponent input) { if (input instanceof JFormattedTextField) { Object o = ((JFormattedTextField)input).getValue(); if (o == null) return true; String value = o.toString(); return CIF_NIF.isNIFOK(value);

} return false;

El mtodo verify() se encarga de llamar al mtodo CIG_NIF.isNIFOK() que contiene el algoritmo de verificacin de DNIs. Si este mtodo da el DNI por bueno, el usuario podr cambiar el
7 La clase CIF_NIF, comentada ms abajo, se incluye en el cdigo fuente de este artculo.

7 de 24

foco. Si no es as, el foco permanecer en el campo de DNI.8

CMO FUNCIONA EN REALIDAD?


En la primera parte de este artculo he intentado que el lector disponga de la informacin suficiente sobre JFormattedTextField para que se anime a usarlo en sus aplicaciones. Buena parte de la informacin que el lector ha encontrado en la primera parte puede, tambin, encontrarla en diversos tutoriales. El de Sun, por ejemplo, nos muestra algunos ejemplos parecidos a los que he descrito. Sin embargo, ni sus ejemplos, ni los que yo he presentado son realmente serios. Simplemente pretenden ilustrar algunas de las funcionalidades bsicas de los distintos elementos implicados en JFormattedTextField. Para esta segunda parte, me he propuesto intentar proporcionar a lector la informacin necesaria para poder usar aquellos aspectos poco evidentes de JFormattedTextField. La informacin que aqu presento es fruto del estudio directo de las distintas APIs implicadas en JFormattedTextField y del cdigo fuente de las distintas clases. Espero que le ahorre trabajo al lector.

Observaciones generales
JFormattedTextField siempre almacena como valor un objeto (una subclase de Object). Este valor, sin embargo, debe ser representado como una tira de caracteres (una String) ya que JFormattedTextField no es sino una subclase de JTextField, quien, como su propio nombre indica, es un campo de texto. Esto no es problema para JTextField, ya que siempre almacena objetos de tipo String, pero para JFormattedTextField no es tan evidente. Alguien tiene que transformar este objeto en una String para que pueda ser representado. Volviendo al nombre de nuestro componente, JFormattedTextField, observamos que contiene el adjetivo formatted (formateado, con formato). Este es un detalle importante. La transformacin del objeto almacenado a String comporta un proceso de aplicacin de formato. Resumiendo, JFormattedTextField : 1. Toma el valor que le asignamos, 2. crea una tira de caracteres convenientemente formateada segn algn criterio y 3. la muestra en el campo Pero hemos comentado ms arriba que el valor no slo se asigna y se ve, sino que se edita. Es decir, que hay un formato de edicin y que quien controla este formato se encarga de decidir, por ejemplo, si en tal posicin podemos escribir un nmero o una letra o si podemos escribir o no en una posicin concreta.

El formato
Los responsables del formato, tanto del de edicin como del de visualizacin, son los formateadores. Un formateador es, en realidad, una clase derivada de JFormattedTextField.AbstractFormatter y cumple diversas funciones. En modo de edicin, decide qu se puede escribir y dnde y cmo y cundo pasa el valor editado al
8 El componente de ejemplo DNIField, descrito ms abajo, se incluye en el cdigo fuente de este artculo.

8 de 24

campo. Por ejemplo, si usamos un formato numrico, y no permitimos la insercin de caracteres incorrectos, no podremos teclear ninguna letra. En el campo de DNI que he puesto de ejemplo, nunca podremos escribir sobre el guin de separacin de la letra de control, a pesar de que MaskFormatter use el modo de sobrescritura por defecto. En algunos casos, el formateador tambin define el comportamiento del teclado. Por ejemplo, DateFormatter permite el incremento o decremento de los distintos campos de una fecha (da, mes, etc.) mediante las flechas del teclado. En modo de visualizacin, decide cmo se muestra el valor almacenado en el campo. As, en la aplicacin de ejemplo MoneyFieldTest, podremos comprobar que el valor almacenado como BigDecimal en un campo MoneyField, en modo de visualizacin, se muestra como un nmero y un carcter de moneda. Un formateador transforma un valor (esto es, un Object) a una tira de caracteres usando el mtodo valueToString(Object) y una tira de caracteres a un valor (esto es, un Object) usando el mtodo stringToValue(String). Estos son los mtodos que le permiten almacenar lo editado como una subclase de Object y mostrar este valor como una tira de caracteres en el campo. La siguiente figura muestra la jerarqua de clases de los distintos formateadores:

Figura 1: Jerarqua de formateadores

El ms sencillo es DefaultFormatter que se utiliza para formatear objetos arbitrarios. El mtodo valueToString(), simplemente, devuelve el resultado del mtodo toString() del valor almacenado. Y para almacenar una tira como valor, usa un constructor de la clase del objeto que tenga como parmetro una tira de caracteres. InternationalFormatter es una subclase de DefaultFormatter que usa java.text.Format para pasar de String a Object y viceversa. Por defecto, slo admite caracteres correctos (setAllowsInvalid(false)), por lo que no es conveniente modificar esta propiedad si no queremos tener problemas. 9 de 24

Tambin se encarga de ajustar la posicin del cursor, situndolo sobre aquellas posiciones en las que se puede escribir. NumberFormatter es una subclase de InternationalFormatter diseada especialmente para la entrada de nmeros. Entre otras cosas, establece el comportamiento de la tecla <menos> de manera que, estemos donde estemos del campo, convierte el nmero entrado en negativo.9 La tecla <ms> pasa el nmero a positivo. Esto es, desaparece el signo menos. DateFormatter es una subclase de InternationalFormatter diseada especialmente para la entrada de fechas. Como hemos comentado ms arriba, define el comportamiento de las flechas del teclado para aumentar o disminuir das, meses, aos, etc. La clase MaskFormatter extiende DefaultFormatter y est pensada especialmente para la edicin de tiras de caracteres con formatos especficos. Como hemos visto ms arriba, se basa en una mscara que indica qu caracteres se pueden escribir en una posicin determinada.

Personalizacin de los formateadores


Todos los formateadores tienen comportamientos por defecto. Por ejemplo, DateFormatter no admite caracteres incorrectos en la edicin y MaskFormatter est siempre en modo de sobrescritura. Pero podemos cambiar alguno de estos comportamientos o acceder a alguna de sus caractersticas ya que nos proporcionan mtodos de acceso. As, DefaultFormatter nos proporciona los siguientes mtodos:10

setAllowsInvalid(boolean): Nos permite decidir si aceptamos caracteres incorrectos o no. setCommitsOnValidEdit(boolean): Nos permite, en modo de edicin, decidir cundo se libra el valor de lo que estamos escribiendo al campo. Si usamos true como parmetro, cada vez que escribamos algo se validar y, si es correcto, se asignar como valor del campo. setOverwriteMode(boolean): Nos permite decidir si la modalidad de edicin es sobrescritura (true) o insercin (false). setMaximum(Comparable): Para establecer el valor mximo admisible por el campo. setMinimum(Comparable): Para establecer el valor mnimo admisible por el campo.11 getFields(int offset): Para determinar qu campo (entero, decimal, signo, etc.) se corresponde con una posicin determinada.12

InternationalFormatter nos ofrece tres posibilidades interesantes como:


9 Curiosamente, si no hemos entrado ningn texto o valor y no permitimos la entrada de caracteres incorrectos, pulsar la tecla <menos> no sirve de nada. 10 En los componentes que he desarrollado de ejemplo, he considerado necesario facilitar el acceso a alguno de los mtodos de personalizacin de formateadores desde el propio componente. As, por ejemplo, los componentes ponen a disposicin del programador mtodos como setOverwriteMode(boolean) o setAllowInvalidCharacters(boolean). 11 Los mtodos setMaximum(Comparable) y setMinimum(Comparable) se han implementado en los componentes de ejemplo DefaultNumberField, IntegerField, DecimalField. Esto permite establecer rangos de valores aceptables para instancias de dichos componentes y de sus subclases PercentField y MoneyField. 12 Vase el mtodo sum(int sign) del componente de ejemplo DefaultNumberField.

10 de 24

A falta de pruebas intensivas, observo que si, habiendo definido un rango de valores aceptable para un InternationalFormater, asignamos un valor fuera del rango definido mediante el mtodo setValue(object), no se tiene en cuenta el rango y el valor se asigna sin problemas al campo.13 MaskFormatter nos obsequia con algunos mtodos realmente tiles:

setInvalidCharacters(String): Nos permite especificar una lista de caracteres que no sern aceptados por el campo. Supongamos, por ejemplo, que tenemos un campo con una mscara para entrar cdigos de producto. La mscara podra ser parecida a sta: U###. Es decir, un carcter alfabtico que ser pasado a maysculas, seguido de tres dgitos. Es de esperar que el usuario no entre una letra acentuada en la primera posicin de la mscara, pero los usuarios son muy listos y seguro que ms de uno lo intentar. Si recordamos la sintaxis para la especificacin de mscaras, observaremos que no hay ninguna manera de especificar que no admitiremos caracteres acentuados. Por lo tanto, el usuario astuto puede entrar una y fastidiarnos la aplicacin. La manera de impedirlo es, pues, usando el mtodo setInvalidCharacters() al que se le pasar como parmetro una String con todos los caracteres acentuados (en maysculas). setValidCharacters(String): Nos permite especificar la lista de caracteres que sern aceptados. Se trata del mtodo complementario del anterior. Siguiendo con el mismo ejemplo, podramos especificar que los caracteres aceptables son ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789. setPlaceHolder(String) y setPlaceHolderChracter(char): permiten, como hemos visto ms arriba, especificar los caracteres que no se mostrarn en las posiciones escribibles. En el ejemplo del campo de DNI, el carcter utilizado era el de subrayado. setValueContainsLitteralCharacters(boolean): Nos permite decidir si los valores entrados, con setValue(), o recuperados, con getValue(), contienen tambin los literales incluidos en la mscara (true) o no (false). As, si nuestra mscara para DNI es ##.###.###-U y hemos especificado true, getValue(), nos devolver 12.345.678-A. Si, por el contrario, especificamos false, nos devolver 12345678A. De igual manera, si hemos especificado true, el parmetro para setValue() tendr que ser 12.345.678-A y si hemos especificado false, 12345678A.

Asignacin de formatos
La nica manera que tenemos de asignar formatos a un JFormattedTextField es mediante una subclase de JformattedTextField.AbstractFormatterFactory. Normalmente, pues, usaremos la nica existente: DefaultFormatterFactory. DefaultFormatterFactory permite especificar cuatro AbstractFormatters para tres situaciones distintas: 1. Formato por defecto: Se usa si no hay otro definido para una situacin concreta, lo cual implica que se usar tanto como formato de edicin como de visualizacin y como nulo, si
13 Esto es debido a las diferencias de comportamiento entre setValue() y commitEdit() que se comentan ms abajo. Este comportamiento ha sido corregido en los componentes numricos de ejemplo. Si se intenta asignar un valor fuera de rango, se lanza una IllegalArgumentException.

11 de 24

slo especificamos ste. 2. Formato de edicin: Se usa cuando el campo tiene el foco y sirve para facilitar la edicin 3. Formato de visualizacin: Se usa cuando el campo no tiene el foco y se utiliza para mostrar el valor 4. Formato nulo: Se usa cuando el campo tiene un valor nulo (null)

Los procesos
En el apartado Observaciones generales, he presentado un breve esquema de los principales procesos que realiza JFormattedTextField para almacenar un valor y mostrarlo. Vamos ahora a entrar con un poco ms de detalle en estos procesos.

Asignacin del valor


Mientras estamos escribiendo, JFormattedTextField no asume, en principio, ningn valor. Lo que escribimos est, por as decirlo, en el aire y slo se puede obtener con el mtodo getText() comn a todos los JtextComponents. La excepcin a dicho comportamiento est en el hecho de especificar setCommitsOnValidEdit(true) para el formateador correspondiente, como hemos comentado ms arriba. Hay dos maneras de asignar un valor al campo: de manera automtica y por programa.

Asignacin de valor automtica


Cuando pulsamos <intro> o cuando cambiamos el foco, empieza el proceso de asignacin automtica de valor. A grandes rasgos, lo que sucede al pulsar <intro> o cambiar el foco es lo siguiente: 1. Ejecuta el mtodo commitEdit(). Este mira si hay un AbstractFormatter definido que se encargue de transformar el texto en un objeto. Si no lo encuentra, no asigna valor. Es decir, si usamos el mtodo getValue() de JFormattedTextField, nos devolver null. 2. Si encuentra el AbstractFormatter, obtendr el texto entrado mediante getText() y usar el mtodo stringToValue() para obtener el objeto correspondiente y asignarlo. El proceso de transformacin de una tira a un objeto, comporta un anlisis de la tira y es posible que no funcione. En este caso, el AbstractFormatter generar una ParseException y no se asignar ningn valor. Un ejemplo tpico sera el intento de asignacin de la tira 1OOO (obsrvese que en vez de ceros hay os maysculas) mediante un NumberFormatter. ste intentar convertir esta tira en un Long y se producir una excepcin. El resultado es que getValue() nos devolver null o el ltimo valor correcto entrado. Pero JFormattedTextField nos permite afinar un poco ms en el caso de la asignacin de valor por cambio de foco y nos permite establecer polticas a seguir. Para ello usaremos el mtodo JFormattedTextField.setFocusLostBehavior(int behavior). La siguiente tabla las resume:

12 de 24

Valor JFormattedTextField.REVERT

Descripcin
Revierte lo editado al ltimo valor almacenado en el campo. Es decir, al valor devuelto por el mtodo getValue(). Si no hay ningn valor almacenado previamente o no forzamos un setValue(), por ejemplo, pulsando <intro>, el contenido de la edicin actual se perder. Entrega el valor actual al perder el foco. Si el valor editado no es considerado un valor legal por el AbstractFormatter (esto es, se lanza una ParseException), entonces el valor editado no cambiar pero no se asignar como valor. Resumiendo, se comporta como COMMIT, pero si el valor editado no es correcto, no limpia el campo.

JFormattedTextField.COMMIT

JFormattedTextField.COMMIT_OR_REVERT Es similar a COMMIT, pero si el valor que escribimos no es legal (esto es, el AbstractFormatter lanza una ParseException), se comporta como REVERT y limpia el contenido del campo. JFormattedTextField.PERSIST No hace nada, no obtiene un nuevo AbstractFormatter y no actualiza el valor. Sea correcto o incorrecto lo que entremos, mantiene el valor correcto anterior pero no limpia el campo.

Tabla 1: Polticas de asignacin de valor en la prdida de foco

La poltica por defecto es COMMIT_OR_REVERT.14

Asignacin de valor por programa


A grandes rasgos, el proceso de asignacin funciona de manera similar a la asignacin automtica. Disponemos de dos mtodos para asignar un valor: setValue(Object valor) y commitEdit(), descrito ms arriba. El ms ms usado es setValue(Object). El proceso, resumido, es el siguiente: 1. Mira si dispone de un formateador (en este caso, mira si hay definida una FormatterFactory). 2. Si no hay ninguna definida, la crea basndose en la clase del objeto pasado como parmetro. Este objeto debe ser una instancia de DateFormat, NumberFormat, Format, Date o Number. JFormattedTextField crear una DefaultFormatterFactory basada en el tipo del valor que intentamos asignar. Si se trata de una instancia de DateFormat,
14 La aplicacin de ejemplo IntegerFieldTest permite hacer pruebas con las distintas polticas de prdida de foco y con el mtodo setCommitsOnValidEdit(boolean).

13 de 24

crear una DefaultFormatterFactory basada en un DateFormatter, si es una instancia de NumberFormat, usar un NumberFormatter, si es una Date, usar DateFormatter, si es un Format, usar InternationalFormatter, si se trata de un Number, usar un NumberFormatter como formateador por defecto y para visualizacin y un NumberFormatter especial que usa un DecimalFormat con el patrn #.# para la edicin. 3. Asigna el valor. Observamos una diferencia notable entre commitEdit() y setValue(). El primero usa el mtodo stringToValue() para obtener el valor a pasar como parmetro de setValue(), mientras que ste asigna el valor directamente. Esto es, commitEdit() puede recibir una ParseException como resultado de invocar stringToValue() si el formateador detecta un error de formato. Hemos de hablar, pues, de un comportamiento asimtrico entre commitEdit() y setValue() que no suele tener consecuencias. Sin embargo, hay algn caso en que esta asimetra comporta algn que otro problema. Veamos un ejemplo: Nosotros construimos un campo para entrada de DNIs con un MaskFormatter, tal y como hemos visto ms arriba. Pero ahora decidimos que el valor del campo no debe contener literales y lo especificamos usando el mtodo valueContainsLitteralCharacters(false). Si asignamos como valor, por ejemplo, 12.345.678-Z, usando setValue(), no se produce ningn error ya que no interviene para nada el formateador. Es ms, getValue() devuelve 12.345.678-Z en vez de 12345678Z.15

15 Esta asimetra ha sido corregida para el componente de ejemplo DNIField. El mtodo setValue() llama siempre al formateador para comprobar errores de formato.

14 de 24

APLICACIONES DE EJEMPLO
Para ilustrar los conceptos tratados en este artculo, he desarrollado una serie de aplicaciones. Dichas aplicaciones se incluyen con el cdigo fuente correspondiente para que el lector pueda estudiarlas y modificarlas a su conveniencia. He procurado que los ejemplos no sean abstractos sino que sean prcticos y usables para cualquier desarrollador. He clasificado los ejemplos en tres categoras: 1. Componentes auxiliares: se usan en las aplicaciones de demostracin y tienen poco que ver con JFormattedTextField. A pesar de ello, creo que algunas de ellas pueden ser bastante interesantes para los desarrolladores. 2. Componentes derivados de JFormattedTextField: son un conjunto de subclases de JFormattedTextField que, a mi entender, cumplen un doble objetivo. Por una parte ilustran la mayor parte de conceptos relacionados con JFormattedTextField y con los distintos formateadores y por otra, constituyen un conjunto de componentes (en ingls, los llamaran widgets) especializados en distintas tareas (entrada de nmeros, porcentajes, fechas y DNIs) listos para ser utilizados por cualquier desarrollador. La estrategia seguida para el desarrollo de los componentes ha sido doble. Por una parte, he aadido funcionalidades que no estn directamente relacionadas con JFormattedTextField, como la aritmtica de fechas, la asignacin de escala a un valor decimal o la autocomplecin de un DNI y, por otro, he hecho emerger, a nivel de componente, propiedades del formateador, como la asignacin dinmica del formato de representacin de fechas o la especificacin de rango para los campos numricos. 3. Aplicaciones de demostracin: se trata de pequeas aplicaciones que ilustran tanto el funcionamiento de los distintos componentes descritos en el punto anterior, como el de algunos aspectos de JFormattedTextField y de los formateadores. A continuacin, paso a describir brevemente cada una de ellas.

Componentes auxiliares
CIF_NIF
Es una clase que proporciona una serie de mtodos estticos para la verificacin de CIFs y NIFs espaoles. Contiene una amplia documentacin sobre las fuentes en las que me he basado para escribirla y la casustica que se trata. Destacara las siguientes funcionalidades:

Determina si una tira se corresponde con un NIF o con un CIF Determina si un NIF o un CIF son correctos Dado un NIF sin letra de control, calcula y devuelve dicha letra Trata NIEs (NIFs para extranjeros)

Esta clase se utiliza en el componente DNIField.

BoundJSpinner
Es una subclase de JSpinner que tiene la propiedad value bound. Esto es, cada vez que el valor 15 de 24

de BoundJSpinner cambia, se genera un PropertyChangeEvent. Se usa en las demostraciones de algunos de los componentes.

ButtonGroupJPanel
Es una subclase de JPanel que facilita el uso de JRadioButons desde un editor visual. Si queremos un comportamiento normal de mutua exclusin de JRadioButons (esto es, que cuando se pulse en uno el que estaba seleccionado deje de estarlo), es necesario aadir todos los JRadioButons a un ButtonGroup. ButtonGroupPanel, se encarga de ello por nosotros. ButtonGroupPanel est basado en un ejemplo de Scott Stanchfield (http://www.javadude.com) y se usa en las demostraciones de algunos componentes.

OverwriteCaret
Es una subclase de DefaultCaret que dibuja un cursor horizontal. Se utiliza para indicar que estamos en modalidad de sobrescritura.

Pair
Un simple bean no visual que mantiene una pareja de tipo clave/descripcin. Se usa en los JCombobox de algunas de las demostraciones de los componentes.

Componentes derivados de JFormattedTextField


Son componentes de ejemplo, usables,16 que llevan a la prctica todo lo que he intentado explicar sobre JFormattedTextField y su entorno. Recomiendo vivamente al lector que estudie con cario el cdigo fuente y lea los javadocs de las distintas clases. Creo que esto va a ser ms prctico (y ms corto) que entrar en los detalles de diseo de cada una de los componentes.

EnhancedJFormattedTextField
Es una interface que establece los mtodos, y por ende las funcionalidades, generales del conjunto de componentes.

DefaultJFormattedTextField
Es una subclase abstracta de JFormattedTextField que implementa la interface EnhancedJFormattedTextField y que contiene cdigo para funcionalidades comunes al resto de los componentes. Destaco las siguientes:

Gestin y creacin de la AbstractFormatterFactory usada por los distintos subcomponentes. Posibilidad de establecer la modalidad de escritura y mostrar un cursor diferente para cada modalidad. La asignacin de dicha funcionalidad a la tecla <ins>, que intercambia las dos modalidades de escritura.

16 A pesar de haber realizado una infinitud de pruebas y de disear y ejecutar pruebas unitarias, puede que los componentes no se comporten como debieran. Los proporciono a guisa de ejemplos y no me responsabilizo de los efectos colaterales que se deriven de su uso en produccin.

16 de 24

Implementa el mtodo clear() que permite borrar el contenido de un campo. Hace accesibles, a nivel de componente, el uso de los mtodos setCommitsOnValidEdit(boolean) y getCommitsOnValidEdit() de DefaultFormatter. Implementa, a nivel de componente, la poltica de aceptacin de caracteres incorrectos del formateador. Implementa, a nivel de componente, la poltica de establecimiento y gestin de rangos de valores aceptables. Implementa el mtodo isEmpty() que nos indica si el campo est vaco..

DefaultNumberField
Es una subclase abstracta de DefaultJFormattedTextField que contiene cdigo para las funcionalidades comunes de los campos numricos (DecimalField, IntegerField, MoneyField y PercentField). Por ejemplo, define el comportamiento del teclado para que las flechas sirvan para incrementar o decrementar el valor almacenado en el campo o permite establecer un rango de valores para los componentes numricos.

DecimalField
Extiende DefaultNumberField adaptndolo a la presentacin y edicin de nmeros decimales. Destacar las siguientes funcionalidades:

Distingue el modo de presentacin, en el que muestra separadores de millares y un carcter de separacin decimal acorde con el Locale, del de edicin, en el que se facilita el uso del teclado numrico Permite establecer diversas polticas de redondeo Permite determinar la escala Los valores entrados se almacenan siempre como BigDecimals Se le puede asignar cualquier valor derivado de Number, pero tambin valores de tipos nativos (int, long, byte, short, float, double, etc.). Internamente, se almacenan como BigDecimals

IntegerField
Es una subclase de DefaultNumberField que facilita la edicin y presentacin de nmeros enteros. Se le puede asignar cualquier valor derivado de Number (si el valor tiene decimales, slo se toma la parte entera) pero tambin valores de tipos nativos (int, long, byte, short, float, double, etc.). Internamente, se almacenan como BigInteger.

MoneyField
Extiende DecimalField asignando como formato de visualizacin el de moneda.

PercentField
Extiende DecimalField asignando como formato de visualizacin el de porcentaje. 17 de 24

DNIField
Es una subclase de DefaultJFormattedTextField que facilita la entrada y validacin de DNIs espaoles mediante una mscara de entrada. Funcionalidades destacables:

Permite determinar si el DNI entrado es correcto (boolean DNIField.isOK()) Permite 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. Permite completar el DNI con la letra de control correcta pulsando <Ctrl-Espacio> o, tambin, cuando el campo pierde el foco. Evita la entrada de letras de control no admisibles para DNIs.

DateField
Es una subclase de DefaultFormattedTextField que facilita la entrada, visualizacin y manejo de fechas y horas. Destaco las siguientes funcionalidades:

Admite valores asignables de tipo Date y Calendar Permite cambiar dinmicamente el formato de visualizacin (el de edicin es el mismo que el de visualizacin) especificando patrones con sintaxis de SimpleDateFormat Implementa una aritmtica simple de fechas. Permite aadir o quitar das, semanas, meses, aos, horas, minutos o segundos a la fecha almacenada como valor en el campo de manera sencilla (p.e. addMonths(3), aadira tres meses, addWeeks(-3) restara tres semanas a la fecha).

StringField
Extiende DefaultFormattedTextField para facilitar la escritura de texto. Si bien Swing nos proporciona ya un campo de texto, JTextField, considero que no es suficiente para cubir algunas de las necesidades ms importantes de un campo de este estilo. As, por ejemplo, JTextField slo nos proporciona un mtodo de escritura, la insercin, y no nos permite determinar la longitud mxima del texto a escribir. Este segundo aspecto es importante si tenemos ligado el texto a alguna columna de una tabla en una base de datos. Si usamos JTextField, no podemos asegurar que el texto entrado por el usuario tenga una longitud inferior o igual a la definida para la columna de la tabla, por lo que nos veremos obligados ha controlar este hecho por programa. StringField nos permite delegar en la interficie dicho control al permitirnos determinar la longitud mxima admisible para el texto. StringField nos permite, tambin, establecer una poltica de recorte para la asignacin de valor. Si la activamos, usando el mtodo setStripOn(boolean), al intentar asignar un valor con una longitud superior a la permitida, ste ser recortado convenientemente antes de ser asignado. Si no la tenemos activada, consecuentemente, lanzar una IllegalArgumentException al intentar asignar un valor con una longitud superior a la permitida.

18 de 24

Aplicaciones de demostracin
Siempre se ha dicho que una imagen (en nuestro caso, una aplicacin visual) vale ms que mil palabras. Es por este motivo que he creado una serie de aplicaciones de escritorio que pretenden ejemplificar las funcionalidades de cada uno de los componentes comentados en el apartado anterior. As, pues, el lector dispone de un ejemplo de uso para cada uno de los componentes derivados de JFormattedTextField:

DecimalFieldTest Ilustra las posibilidades de DecimalField IntegerFieldTest Ilustra las posibilidades de IntegerField y las distintas polticas de comportamiento de JFormattedTextField con la prdida de foco. Tambin muestra las posibilidades de uso de setAllowsInvalid(). Permite, a su vez, verificar las asignaciones de valor cuando hay prdida de foco en funcin de la poltica definida. MoneyFieldTest Ilustra las posibilidades de MoneyField PercentFieldTest Ilustra las posibilidades de PercentField DNIFieldTest Ilustra las posibilidades de DNIField DateFieldTest Ilustra las posibilidades de DateField StringFieldTest Ilustra las posibilidades de StringField

Estas aplicaciones se pueden ejecutar por separado o bien a travs de la clase Pruebas que nos permite decidir qu aplicacin ejecutar. Los ejemplos de uso son, creo, bastante intuitivos, sin embargo, hay algunos trucos poco evidentes:

En la aplicacin DNIFieldTest, no hace falta escribir siempre la letra del DNI, si se han entrado todos los nmeros del DNI, basta con pulsar Ctrl-Espacio y la letra correcta aparecer por arte de magia. Si lo que sucede es que la letra entrada es incorrecta, tambin se puede recurrir a Ctrl-Espacio para que se cambie por la correcta. En la aplicacin DateFieldTest, despus de especificar un nuevo patrn, podemos activarlo pulsando el botn OK o bien pulsando intro en el campo de patrn. Tambin es importante tener en cuenta que en el campo Aadir, podemos especificar cantidades negativas para que reste. En los ejemplos IntegerFieldTest y DNIFieldTest, la combinacin de teclas <ctrl-v>, cuando el foco est en el campo, abren un dilogo que muestra el valor del campo.

19 de 24

Arquitectura de clases
La siguiente figura nos muestra el diagrama de clases de los componentes de ejemplo derivados de JformattedTextField. Tngase en cuenta que el diagrama no incluye todos los mtodos.

Figura 2: Diagrama de clases de los componentes de ejemplo

20 de 24

21 de 24

EPLOGO
Es notable el aparente cambio de estrategia de Sun proporcionando en la versin 1.4 de Java dos nuevos componentes Swing que intentan cubrir vacos importantes en lo que al desarrollo de interficies grficas se refiere. Lamentablemente, la versin 5.0 no incluye ningn componente nuevo ni mejora los anteriores. JFormattedTextField nos permite desarrollar aplicaciones ms profesionales y mejora la imagen de Swing. Tenemos mscaras, campos de fecha con un comportamiento razonable, podemos usar diversos formateadores para personalizar nuestros campos, etc. Sin embargo, durante el tiempo que me ha llevado construir este artculo, he encontrado algunos obstculos que me han dificultado la labor de escribir tanto el texto del artculo como los componentes de ejemplo. He encontrado, y es una opinin personal, problemas de ortogonalidad, algunos de los cuales ya he expuesto, como la diferencia de comportamiento de commitEdit() y setValue() que, combinados con la admisin o no de literales en el valor del MaskFormatter, me han dado algn que otro quebradero de cabeza. En el mismo orden de cosas estara el establecimiento de rangos de InternationalFormatter. Siguiendo con la ortogonalidad, me pregunto dnde est el model de JformattedTextField? Ciertamente, sigue siendo el mismo que el de su padre, JTextField, un PlainDocument. Sin embargo, las relaciones entre vista/controlador (delegate) y modelo, ni son tan claras como en JTextField ni se cuentan en parte alguna. Me he encontrado tambin con problemas de visibilidad (scope) cuando he intentado extender, por ejemplo, DefaultFormatter. Hay mtodos importantes de DefaultFormatter y de JTextComponent que slo estn visibles a nivel de package y que dificultan extender tanto DefaultFormatter como AbstractFormatter. Es realmente complejo extender los formateadores que nos vienen dados. En el proceso de creacin de este artculo, me propuse reproducir un componente que haba desarrollado hace tiempo como una extensin de JTextField y que ofreca una funcionalidad sencilla pero prctica: determinar el nmero mximo de caracteres que poda aceptar un campo de entrada. Ante la dificultad de extender DefaultFormatter, decid ir directamente a PlainDocument y atacar el modelo como hice anteriormente. Bien, no acab de funcionar. El mtodo insertString() de AbstractDocument no se invoca al insertar una tira (por teclado o desde el clipboard) como en JTextField, sino cuando el campo cambia de foco. La falta de tiempo y las dificultades han hecho que abandonara esta lnea. Finalmente, y para la versin 1.1 de este artculo, he desarrollado StringField, pero recurriendo al control de la propiedad value, ya que las otras vas, a mi entender ms coherentes, han resultado imposibles de seguir (posiblemente por mis limitaciones personales). A pesar de los pesares, creo que JFormattedTextField es un componente importante que debe formar parte, de manera habitual, en nuestras aplicaciones. Deseo que el lector pueda, con la ayuda de este artculo, sortear mejor que yo las dificultades de creacin de componentes derivados de JFormattedTextField y que este artculo contribuya a hacer un mejor y mayor uso de Swing en sus aplicaciones de escritorio.

22 de 24

QU HE USADO?
He usado Eclipse 3.0.1 (http://www.eclipse.org) para el desarrollo, la generacin de Javadocs y las pruebas unitarias con JUnit 3.8.1 (http://www.junit.org). Para el desarrollo de las interficies de usuario en Swing, he usado el Visual Editor de Eclipse (http://www.eclipse.org/vep/) en su versin 1.0.2.1RC2. Para la generacin del diagrama de clases de los componentes, he usado la ltima versin del plugin de Eclipse Omondo EclipseUML (http://www.omondo.com/index.html). Este artculo ha sido escrito con OpenOffice 2.0 beta (http://www.openoffice.org/) y ste tambin se ha usado para la generacin del PDF.

QU HE LEDO?
Realmente, hay poca literatura que haga referencia a JformattedTextField. Yo slo he encontrado un par de tutoriales que cubren los aspectos ms bsicos. El primero, siempre es una referencia, es el captulo How to Use Formatted Text Fields (http://java.sun.com/docs/books/tutorial/uiswing/components/formattedtextfield.html) del tutorial oficial de Java. Es correcto, pero creo que insuficiente si quieres trabajar a fondo con las posibilidades de JformattedTextField. Expone con claridad algunos conceptos bsicos. El segundo, es el artculo de John Zukowski Swing's new JFormattedTextField component (http://www-106.ibm.com/developerworks/java/library/j-mer0625/) de junio de 2002 dentro de la interesante serie de artculos sobre novedades de la versin 1.4 de Java Magic with Merlin que el autor ha publicado en developerWorks. Bien escrito pero muy bsico. Como he comentado ms arriba, para entender el funcionamiento de JFormattedTextField, he tenido que leer mucha API y bastante cdigo fuente.

INSTALACIN, CONTENIDO Y EJECUCIN


Este tutorial y los archivos relacionados estn empaquetados en un archivo ZIP. Al descomprimirlo (respetando la estructura de directorios) se crear el subdirectorio JFTF que contiene:

El archivo LEEME.TXT que explica, como aqu, qu contiene el directorio y cmo se usa. Este artculo en formato PDF. El archivo jftf.jar que contiene los componentes de ejemplo, las aplicaciones de demostracin y los tests unitarios. El subdirectorio src que contiene el cdigo fuente. El subdirectorio bin con las classes compiladas. El subdirectorio doc que contiene los javadoc de todas las clases.

Ejecucin de las aplicaciones de ejemplo


Las aplicaciones de ejemplo se pueden ejecutarse por separado o bien, yo lo recomiendo, ejecutando la clase com.froses.jftf.widgets.demo.Pruebas: 23 de 24

java -classpath jftf.jar com.froses.jftf.widgets.demo.Pruebas

o bien
java -jar jftf.jar

desde el directorio [...]\JFTF creado al descomprimir el archivo ZIP del artculo. Si el lector est usando un entorno Windows, puede, simplemente, hacer doble clic sobre el archivo jftf.jar.

Estructura del cdigo fuente


El cdigo est organizado en cinco packages: 1. com.froses.jftf.tools: Contiene los componentes auxiliares CIF_NIF y Pair. 2. com.froses.jftf.widgets: Contiene los componentes de ejemplo derivados de JFormattedTextField. 3. com.froses.jftf.widgets.demo: Contiene las aplicaciones de demostracin. 4. com.froses.jftf.widgets.tools: Contiene los componentes auxiliares grficos:

BoundJSpinner ButtonGroupJPanel OverwriteCaret

24 de 24

You might also like