Los campos de texto muestran una sla lnea de texto selecionable y
opcionalmente editable. Generalmente se usa la clase JTextField para proporcionar campos de texto. Si necesitamos proporcionar un campo de password -- un campo de texto editable que no muestre los caracteres tecleados por el usuario -- se utiliza la clase JPasswordField. Esta pgina describe ambas clases. Si queremos que un campo de texto que tambin proporcione un men de strings de las que eligir, podemos considerar la utilizacin de un combo box editable. Si necesitamos obtener ms de una lnea de entrada del usuario, deberamos usar una las clases que implementan reas de texto de propsito general. Este applet es una versin Swing del programa AWT descrito en Cmo usar Campos y reas de Texto. El Applet muestra un campo de texto bsico y un rea de texto. El campo de texto es editable y el rea no. Cuando el usuario pulsa el botn Return en el campo de texto, dispara un evento action. El applet reacciona al evento copiando el contenido del campo de texto en el rea de texto y luego seleccionando todo el texto del campo de texto. Podemos encontrar el cdigo fuente del programa en TextDemo.java. El correspondiente fichero HTML, TextDemo.html, contiene una etiqueta <APPLET> para ejecutar el applet. Aqu est el cdigo de TextDemo que crea el campo de text en el applet: textField = new JTextField(20); ... getContentPane().add(textField); ... textField.addActionListener(this); El constructor de JTextField toma un prametro entero indicando el nmero de columnas del campo de texto. Las siguientes lneas de cdigo aaden el campo de texto al panel de contenido del applet, y registra el applet como oyente de actin del campo de texto. Aqu est el mtodo actionPerformed que maneja los eventos action del campo de texto: public void actionPerformed(ActionEvent evt) { String text = textField.getText(); textArea.append(text + newline); textField.selectAll(); } Este ejemplo ilustra el uso de un campo de texto bsico y autocontenido para introducir datos textuales y realizar alguna tarea cuando el campo de texto dispara un evento action. Esto es suficiente para muchos programas. Otros, sin embargo, necesitan un comportamiento ms avanzado. Como una subclase de JTextComponent, JTextField puede ser configurada y personalizada. Una personalizacin comn es proporcionar un campo de texto cuyos contenidos sean validados. Este tpico y otros ms se cubren en las siguientes secciones: Crear un Campo de Texto Validado Usar un Oyente de 'Document' en un Campo de Texto Distribuir las parejas etiqueta/campo de texto Proporcionar un Password Field El API Text Field Ejemplos que usan Text Fields Crear un Campo de Texto Validado Muchos programas requieren que los usuarios introduzcan datos textuales de un cierto tipo o formato. Por ejemplo, un programa podra proporcionar un campo de texto para introducir una fecha, un nmero decimal, o un nmero de telfono. El contenido de dichos campos debe ser validado antes de usarlos para cualquier propsito. Un campo de texto puede ser validado- action(accin) o validadokeystroke(pulsacin). Los datos en un campo validado-action se chequean cada vez que se dispara un evento actin (cada vez que el usuario pulsa la tecla Return). Un campo validado-action podra, en un momento dado, contener datos no vlidos. Si embargo, los datos son validados antes de utilizarlos para otra cosa. Para crear un campo validado-action, proporcionamos un oyente de 'action' para nuestro campo e implementamos su mtodo actionPerformed de esta forma: Usar getText para obtener el contenido del campo de texto. Evaluar el valor devuelto por getText. Si el valor es vlido, hacer las tareas o clculos requeridos. Si el valor no es vlido, informar del error y volver sin realizar la tarea o clculo. En un campo validado-keystroke los datos se chequean cada vez que cambian. Una campo validado-keystroke nunca puede contener datos no vlidos porque cada pulsacin hace que el dato no vlido sea rechazado. Para crear un campo de texto validado-keystroke necesitamos proporcionar un documento personalizado a nuestro campo de texto. Si no ests familiarizado con los documentos, puedes ver la seccin Trabajar con el Documento de un Componente de Texto.
Aviso: No se usa un oyente de 'Document' para validacin de pulsaciones. El momento en que el documento nitifica un cambio es demasiado tarde, el cambio ya ha tenido lugar. Puedes leer los dos ltimos parrfos de la seccin Escuchar los Cambios en un Documento para ms informacin.
La aplicacin mostrada en la siguiente figura tiene cuatro campos de texto validados-keystroke. El usuario introduce la informacin en los tres primeros campos. Cada vez que el usuario teclea un caracter, el programa valida la entrada y actualiza el resultado en el cuarto campo de texto.
Intenta esto: 1. Compila y ejecuta la aplicacin. El fichero fuente es TextFieldDemo.java. Tambin necesitars WholeNumberField.java, DecimalField.java, y FormattedDocument.java. 2. Introduce informacin en los campos de texto y mira el resultado. Si intentas introducir datos no vlidos, el programa hace sonar un beep. 3. Intenta teclear algo en el cuarto campo de texto. No puedes porque no es editable. Sin embargo, se puede seleccionar el texto. 4. Redimensiona la ventana. Observa que las etiquetas y los campos de texto permanecen alienados. En Distribuir las Parejas Etiqueta/Campo de Texto hay ms informacin sobre esta caracterstica del programa.
El campo Years es un ejemplar de WholeNumberField.java, que es una subclase de JTextField. Sobreescribiendo el mtodo createDefaultModel, WholeNumberField establece una subclase de Documentpersonalizada - un ejemplar de WholeNumberDocument -- como el documento de cada WholeNumberField creado: protected Document createDefaultModel() { return new WholeNumberDocument(); } Aqu est la implementacin de WholeNumberDocument: protected class WholeNumberDocument extends PlainDocument {
public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
char[] source = str.toCharArray(); char[] result = new char[source.length]; int j = 0;
for (int i = 0; i < result.length; i++) { if (Character.isDigit(source[i])) result[j++] = source[i]; else { toolkit.beep(); System.err.println("insertString: " + source[i]); } } super.insertString(offs, new String(result, 0, j), a); } } Esta clase sobreescribe el mtodo insertString que es llamado cada vez que se va a insertar un string o un caracter en el documento. La implementacin que hace WholeNumberDocument de insertStringevalua cada caracter a insertar en el campo de texto. Si el caracter es un dgito, el documento permite que sea insertado. De otro modo, el mtodo hace un beep e imprime un mensaje de error. Por lo tantoWholeNumberDocument permite los nmeros en el rango 0, 1, 2, ... Un interesante detalle de implementacin es que nuestro documento personalizado no tiene que sobreescribir el mtodo remove. Este mtodo es llamado cada vez que se elimina un caracter o un grupo de caracteres del campo de texto. Como eliminar un dgito de un entero no puede producir un resultado no vlido, esta clase no le presta atencin a las eliminaciones. Los otros dos campos de entrada del ejemplo, as como el campo no editable Monthly Payment, son todos ejemplares de DecimalField.java, una subclase personalizada de JTextField. DecimalField usa un documento personalizado FormattedDocument, que slo permite la introduccin de datos en un formato particular. FormattedDocument no tiene conocimineto del formato real de su contenido. En su lugar, FormattedDocument relega el formato en una subclase de Format, para aceptar o rechazar un cambio propuesto. El campo de texto que usa el FormattedDocument decide que formato utilizar. Los campos de texto Loan Amount y Monthly Payment usan un objeto NumberFormat creado de esta forma: moneyFormat = NumberFormat.getCurrencyInstance(Locale.US); ((DecimalFormat)moneyFormat).setPositiveSuffix(" "); El siguiente cdigo crea el formato del campo de texto APR: percentFormat = NumberFormat.getPercentInstance(Locale.US); percentFormat.setMinimumFractionDigits(3); Como muestra el cdigo, la misma clase (NumberFormat) puede soportar un formato de moneda y otro de porcentaje. Adems, Format y sus subclases son sensibles a la localidad, por eso el campo decimal puede crearse para soportar formatos de otros paises o regiones. Puedes ver la pgina Formatear nmeros en la seccin de internacionalizacin para informacin ms detalladas sobre los formatos. Aqu est la implementacin que hace FormattedDocument de insertString: public void insertString(int offs, String str, AttributeSet a) throws BadLocationException {
try { format.parseObject(proposedResult); super.insertString(offs, str, a); } catch (ParseException e) { Toolkit.getDefaultToolkit().beep(); System.err.println("insertString: could not parse: " + proposedResult); } } El mtodo usa el formateador para analizar el resultado de la insercin propuesta. Si el resultado se formatea correctamente, el mtodo llama al mtodo insert de su superclase para realizar la insercin. Si el resultado no se formatea correctamente, el ordenador hace un beep. Adems de sobreescribir el mtodo insertString, FormattedDocument tambin sobreescribe el mtodo remove. Recuerda que este mtodo es llamado cada vez que se elimina del documento un caracter o un grupo de caracteres. public void remove(int offs, int len) throws BadLocationException { String currentText = getText(0, getLength()); String beforeOffset = currentText.substring(0, offs); String afterOffset = currentText.substring(len + offs, currentText.length()); String proposedResult = beforeOffset + afterOffset;
try { if (proposedResult.length() != 0) format.parseObject(proposedResult); super.remove(offs, len); } catch (ParseException e) { Toolkit.getDefaultToolkit().beep(); System.err.println("remove: could not parse: " + proposedResult); } } La implementacin del mtodo remove es similar al mtodo insertString. El formateador analiza el resultado del cambio propuesto y realiza la eliminacin o no, dependiendo de si el resultado es vlido. Usar un Oyente de 'Document' sobre un campo de texto Por eso, si no podemos usar un oyente de 'document' para validacin de campos, que podemos utilizar? Podemos usar un oyente de, pero no interferir con, los cambios del contenido del documento. El calculador de crditos usa el siguiente oyente de 'document' para actualizar el pago mensual despus de cada cambio: class MyDocumentListener implements DocumentListener { public void insertUpdate(DocumentEvent e) { update(e); } public void removeUpdate(DocumentEvent e) { update(e); } public void changedUpdate(DocumentEvent e) { // we won't ever get this with a PlainDocument } private void update(DocumentEvent e) { Document whatsup = e.getDocument(); if (whatsup.getProperty("name").equals("amount")) amount = amountField.getValue(); else if (whatsup.getProperty("name").equals("rate")) rate = rateField.getValue(); else if (whatsup.getProperty("name").equals("numPeriods")) numPeriods = numPeriodsField.getValue(); payment = computePayment(amount, rate, numPeriods); paymentField.setValue(payment); } } Este es un uso apropiado de un oyente de 'document'. Para ms informaicn sobre los oyentes de 'document' puedes ver la pgina Cmo escribir un Oyente de 'Document'. Distribuir las parejas Etiqueta/Campo de Texto Las filas de parejas etiqueta/campo de texto como las encontradas en el calculador de crditos son bastante comunes en paneles de preferencias y paneles de formularios. Aqu est el cdigo que distribuye las parejas de etiquetas y campos de texto: . . . //Layout the labels in a panel JPanel labelPane = new JPanel(); labelPane.setLayout(new GridLayout(0, 1)); labelPane.add(amountLabel); labelPane.add(rateLabel); labelPane.add(numPeriodsLabel); labelPane.add(paymentLabel);
//Layout the text fields in a panel JPanel fieldPane = new JPanel(); fieldPane.setLayout(new GridLayout(0, 1)); fieldPane.add(amountField); fieldPane.add(rateField); fieldPane.add(numPeriodsField); fieldPane.add(paymentField);
//Put the panels in another panel, labels on left, //text fields on right JPanel contentPane = new JPanel(); contentPane.setBorder(BorderFactory.createEmptyBorder(20, 20, 20, 20)); contentPane.setLayout(new BorderLayout()); contentPane.add(labelPane); contentPane.add(fieldPane, "East");
setContentPane(contentPane); . . . Podras haberte sorprendido de encontrar que las etiquetas se distribuyen sin referencias a los campos de texto y, de hecho, estn en paneles diferentes, se alinean correctamente con ellos. Esto es un efecto lateral de los controladores de distribucin usados por el programa.
Como ilustra el diagrama, el programa usa dos controladores GridLayout, uno para la columna de etiquetas y otro para la columna de campos de texto. GridLayout garantiza que todos sus componentes tendrn el mismo tamao, por eso todos los campos de texto tienen la misma altura y todas las etiquetas tambin. Para conseguir la alineacin de las etiquetas y los campos de texto, el programa usa un tercer controlador de distribucin, un BorderLayout. Con slo dos componentes como East y Center, BorderLayoutgarantiza que las columnas tengan la misma altura. As las etiquetas y los campos de texto se alinean. Proporcionar un Campo de Password Swing proporciona la clase JPasswordField, una subclase de JTextField, para usarla en vez de un campo de texto cuando el texto introducido por el usuario es una password. Por razones de seguridad, un campo de password no muestra los caracteres tecleados por el usuario. En su lugar muestra otros caracteres como asteriscos "*". El ejemplo PasswordDemo descrito en Usar la clase SwingWorker usa un JPasswordField. El program trae una pequea ventana para pedir al usuario que teclee una password:
Aqu est el cdigo de PasswordDemo que crea y configura el campo de password: JPasswordField password = new JPasswordField(10); password.setEchoChar('#');
password.addActionListener(showSwingWorkerDialog); El argumento pasado al constructor de JPasswordField indica que el campo debera tener 10 columnas de ancho. Por defecto un campo de password muestra un asterico '*' por cada caracter tecleado. La llamada a setEchoChar lo cambia por una almohadilla '#'. Finalmente el cdigo aade un oyente de 'action' al campo de password. El mtodo actionPerformed del oyente obtiene la password tecleada por el usuario y la verifica con este cdigo: public void actionPerformed(ActionEvent e) { JPasswordField input = (JPasswordField)e.getSource(); char[] password = input.getPassword(); if (isPasswordCorrect(password)) JOptionPane.showMessageDialog(f, worker.get()); else JOptionPane.showMessageDialog(f, new JLabel("Invalid password.")); } Este mtodo usa el mtodo getPassword del campo de password para obtener el contenido del campo. Observa que getPassword devuelve un array de caracteres. La informacin de un password no debera almacenarse ni pasarse en strings porque stas no son seguras. Por eso no uses getText o setText sobre un campo de password. En su lugar usa getPassword o setPassword porque estos mtodos usan arrays de caracteres en vez de strings.
Nota: El mtodo getPassword y su compaero, setPassword, no existan en Swing 1.0.3 y anteriores. En estas versiones se debe usar getText y setText. Nuestro programa debera almacenar cualquier passwrod en un array de caracteres y convertirlo temporalmente a un string cuando se llame a getText o a setText.
El API de TextField Las siguientes tablas muestran los mtodos y constructores ms usados de JTextField. Otros mtodos interesantes los proporcionan las clases JComponent y Component. Adems, podramos querer llamar a alguno de los mtodos definidos por JTextComponent, la clase padre de JTextField. Puedes ver la seccin: El API de los Componentes de Texto. El API para usar campos de texto se divide en tres categoras: Seleccionar u Obtener el Contenido de un Campo de Texto Ajuste Fino de la apariencia de una Campo de Texto Implementar la Funcionalidad de un Campo de Texto Seleccionar u Obtener el Contenido de un Campo de Texto Mtodo Propsito JTextField() JTextField(String) JTextField(String, int) JTextField(int) JTextField(Document, String, int) Crea un ejemplar de JTextField, inicializando su contenido con el texto especificado. El argumento int indica el nmero de columnas. Esto se utiliza para calculo la anchura preferida del componente y podra no ser el nmero real de columnas mostradas. void setText(String) String getText() Selecciona u obtiene el texto mostrado por el campo de texto. Ajsute Fino de la Aperiencia del Campo de Texto Mtodo Propsito void setEditable(boolean) boolean isEditable() Selecciona u obtiene si el usuario puede editar el campo de texto. void setForeground(Color) Color getForeground() Selecciona u obtiene el color del texto dentro del campo de texto. void setBackground(Color); Color getBackground() Selecciona u obtiene el color del fondo del campo de texto. void setFont(Font); Font getFont() Selecciona u obtiene la fuente usada por el campo de texto. void setColumns(int); int getColumns() Selecciona u obtiene el nmero de columnas mostradas por el campo de texto. int getColumnWidth() Obtiene la anchiura de las columnas del campo de texto. Este valor los establece implcitamente la fuente elegida. void setHorizontalAlignment(int); int getHorizontalAlignment() Selecciona u obtiene cmo est alineado el texto horizontalmente dentro de su rea. Podemos usar JTextField.LEFT, JTextField.CENTER, y JTextField.RIGHTcomo argumentos. Implementar la Funcionalidad del Campo de Texto Mtodo Propsito void addActionListener(ActionListener) void removeActionListener(ActionListener) Aade o elimina un oyente de 'action'. Document createDefaultModel() Sobreescribe este mtodo para proporcionar al campo de texto un documento personalizado. Ejemplos que usan Text Fields Esta tabla lista los ejemplos que usan JTextField y dnde encontrarlos. Ejemplo Dnde se Describe Notas TextDemo.java Esta pgina Usa un textfield con un oyente de 'action'. TextFieldDemo.java Esta pgina Implementa dos campos diferentes con validacin de pulsaciones. PasswordDemo.java Esta pgina y Usar SwingWorkerClass Usa un campos de password. CustomDialog.java Cmo crear un Dilogo Incluye un campo de texto cuyo valor es comprobado.