Beginning Sistemas de Información Java Cuadros de texto Listado siguiente
PresentaciónEntrada/SalidaBibliotecasSwingMarcosBotonesCuadros de texto
ListasImágenesMenúsDiálogosArchivosGráficos 2D 

Generalidades
El componente de texto más usado es JTextField. Los métodos de acceso a su contenido son, como cabía esperar, getText() y setText(). Se puede especificar el número de caracteres de anchura de que consta a través del constructor. Sólo admite una línea de texto. Cuando el usuario pulsa INTRO, se activa el método actionPerformed() del ActionListener asociado al campo de texto, si existe.
Si se desea un cuadro de texto adecuado para insertar contraseñas, debe utilizarse JPasswordField, una variante de JTextField que no muestra en pantalla la contraseña ni permite copiar su contenido.
Otro componente de texto importante es JTextArea. A diferencia de JTextField, admite múltiples líneas de texto.
Por último, Java permite manejar fácilmente documentos de texto cuyo contenido no se limite estrictamente a código ASCII. Véase la documentación correspondiente a JEditorPane, que permite editar correctmente texto puro, código HTML y código RTF.

Ejercicio.- Crear un programa que solicite una contraseña e indique al usuario si esta es correcta o incorrecta.

Una posible solución sería la que puede verse en estas imágenes.

Este es el aspecto que presenta la aplicación cuando el usuario introduce la contraseña, pero sin pulsar Intro.
El usuario ha insertado una contraseña incorrecta y ha pulsado Intro.
El usuario ha escrito la contraseña correcta y ha pulsado Intro


/** 
 * DemoPassword.java
 *
 * Descripción: 
 * @author   coti
 * @version   1.1
 */

import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Font;
import java.awt.GridLayout;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;

public class DemoPassword extends JPanel implements ActionListener {
 JPasswordField jpf;
 JLabel resultado;
 public DemoPassword() {
  JPanel campo = new JPanel(new GridLayout(0,2));
  
  JLabel jl_pwf = new JLabel("Escriba la contraseña: ");
  resultado = new JLabel("******************");
  Font f = new Font("SansSerif", Font.PLAIN, 24);
  resultado.setFont(f);
  resultado.setHorizontalAlignment(JLabel.CENTER);

  jpf = new JPasswordField(10);
  jpf.addActionListener(this);
  
  jl_pwf.setLabelFor(jpf);
  
  campo.add(jl_pwf);
  campo.add(jpf);
  
  setLayout(new BorderLayout());
  add(campo,BorderLayout.NORTH);
  add(resultado, BorderLayout.CENTER);
 }

 public void actionPerformed(ActionEvent ae) {
  /*
   No se debe utilizar getText()
  */
  String st = new String(jpf.getPassword());
  if (st.equals("aladino"))
   resultado.setText("*****CORRECTO****");
  else
   resultado.setText("NO ES CORRECTO");
 }
 static public void main(String[] args) {
  JFrame jf = new JFrame();
  jf.getContentPane().add(new DemoPassword());
  jf.addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent we) {
    System.exit(0);
   }
  });
  jf.pack();
  jf.setVisible(true);
 }
 
}


Comentarios.- El cuadro de texto creado con JPasswordField es análogo al creado con JTextField, salvo sus características de seguridad. De hecho, no se debe recuperar el texto proporcionado mediante getText(), sino que es preciso utilizar getPassword(), que proporciona un char[] en lugar de un String. Esto supone una cierta medida de seguridad, y quizá algo más de comodidad a la hora de comprobar contraseñas que puedan contener caracteres poco habituales.



Ejercicio.- Construir una aplicación basada en JTextArea que permita ejecutar órdenes de una shell y ver en pantalla los resultados de las órdenes ejecutadas. Consultar la documentación de la clase Runtime (especialmente el método getRuntime()) y de la clase Process (especialmente el método exec()).

El programa podría tener el aspecto siguiente:

/** 
 * DemoTextArea.java
 *
 * Description: 
 * @author   coti
 * @version   
 */
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Font;
import java.awt.GridLayout;
import java.awt.Toolkit;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JFrame;
import javax.swing.JPasswordField;
import java.awt.event.KeyEvent;
import java.awt.event.KeyAdapter;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JScrollPane;
import javax.swing.JTextArea;
import java.io.*;
import java.lang.Runtime;
import java.util.StringTokenizer;


public class DemoTextArea extends KeyAdapter {
 JTextArea jta;
 boolean ejecutando;
 public DemoTextArea() {
  JFrame jf = new JFrame("Demostración de TextArea");
  jta = new JTextArea(25,80);
  jta.setForeground(Color.green);
  jta.setBackground(Color.black);
  jta.setFont(new Font("Monospaced", Font.PLAIN, 12));
  JScrollPane jsp = new JScrollPane(jta);
  jta.setLineWrap(true);
  jta.setWrapStyleWord(true);
  jta.addKeyListener(this);
  /*
   jta puede solicitar el foco.
  */
  jta.setRequestFocusEnabled(true);
  jf.getContentPane().add(jsp);
  jf.pack();
  jf.setVisible(true);
  jf.addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent we) {
    System.exit(0);
   }
  });
  /*
   Este es el momento de solicitar el foco.
  */
  jta.requestFocus();
  jta.append("Escriba sus órdenes...\n\n");
  jta.getCaret().setDot(jta.getText().length());
 }
 public void ejecutar(String orden) {
  StringBuffer texto = new StringBuffer();
     try
      {
    String linea = null;

    Process p = Runtime.getRuntime().exec(orden);
    
    BufferedReader rs = new BufferedReader(new InputStreamReader(p.getInputStream()));
    
    linea = "*";
    while (null != linea) {
     linea = rs.readLine();
     System.out.println(linea);
     if (null != linea)
      texto.append(linea+"\n");
    }
    rs.close();
       } 
     catch (Exception err)
      {
        texto = new StringBuffer("Perdon, esa orden no es válida.\n");
        System.out.println("\nLa excepción es: "+err);
       }
      jta.append(texto.toString());
    }//Ejecutar(orden)

 public void keyTyped(KeyEvent ke) {
  char tecla = ke.getKeyChar();
  if (!ejecutando && tecla=='\n')
   {
    String tx = jta.getText(), orden;
    int pos = tx.lastIndexOf("\n", tx.length()-2);
    orden = tx.substring(pos+1);
    System.err.println("La orden es " + orden);
    ejecutando=true;
    ejecutar(orden);
    ejecutando=false;
   };
  super.keyTyped(ke);
 }
 static public void main(String[] args) {
  new DemoTextArea();
 }
 
}



Comentarios.- Esta versión del programa, muy poco sofisticada, hace uso de la versión más sencilla posible de exec(). Por esta razón, sólo será posible ejecutar algunas órdenes (ls -al, pwd, mv, etc). El lector interesado puede consultar los recursos de Internet; existen varios productos que llegan a emular distintas terminales y están escritos tomando como base este método para hacer las cosas.



Ejercicio.- Construir un programa que admita dos matrices y muestres su suma, resta y producto. El programa debe utilizar la metáfora de tarjetas (CardLayout) y empleará botones para conmutar entre tarjetas.

La solución que proponemos se basa en las clases siguientes:

La clase principal es DemoCamposTexto.java, lugar en que se aplica el CardLayout a un JFrame3. Obsérvese que esta variante de JFrame centra el marco en pantalla y se asegura de que tenga el tamaño correcto. El programa se completa con un panel dedicado a botones, que gobierna la visualización de otros dos paneles dedicados a datos y resultados respectivamente. Cada uno de estos dos últimos paneles se va a mostrar en una tarjeta diferente.

DemoCamposTexto.java
/** 
 * DemoCamposTexto.java
 *
 * Description: 
 * @author   Coti
 * @version   
 */

import javax.swing.JPanel;
import java.awt.BorderLayout;
import java.awt.CardLayout;

public class DemoCamposTexto extends JPanel{
 JPanelDatos jpd;
 JPanelBotones jpb;
 JPanelResultados jpr;
 JPanel centro;
 CardLayout cl;
 
 public DemoCamposTexto() {
  cl = new CardLayout();
  centro  = new JPanel(cl);
  
  jpd = new JPanelDatos();
  jpr = new JPanelResultados();

  
  centro.add(Dim.DATOS,jpd);
  centro.add(Dim.RESULTADOS,jpr);
  
  jpb = new JPanelBotones(jpd, jpr, cl, centro);
  
  setLayout(new BorderLayout());
  add(centro, BorderLayout.CENTER);
  add(jpb, BorderLayout.NORTH);
 }

 static public void main(String[] args) {
  new JFrame3("Demostración de campos de texto", new DemoCamposTexto());
 }
 
}



Dim.java
public class Dim {
 public static final int FILAS = 2;
 public static final int COLUMNAS = 2;
 public static final int ANCHURA_CAMPO = 10;
 public static final char ACCION_DATOS = 'a';
 public static final char ACCION_RESULTADOS = 'b';
 public static final String DATOS = "Datos";
 public static final String RESULTADOS = "Resultados";
}


FloatTextField.java
import java.awt.Toolkit;
import javax.swing.JTextField;
import javax.swing.text.Document;
import javax.swing.text.AttributeSet;
import javax.swing.text.BadLocationException;
import javax.swing.text.PlainDocument;

public class FloatTextField extends JTextField {
 
     public FloatTextField(int columnas) {
         super(columnas);
     }
 
     protected Document createDefaultModel() {
        return new DocumentoFloat();
     }
 
     static class DocumentoFloat extends PlainDocument {
 
         public void insertString(int offs, String str, AttributeSet a) 
            throws BadLocationException {
 
            if (str == null) {
          return;
            }
            try
             {
              Float.parseFloat(str);
             }
            catch(Exception e)
             {
              str = null;
              Toolkit.getDefaultToolkit().beep();
             }
            super.insertString(offs, str, a);
        }
     }
 }



JFrame3.java
/** 
 * JFrame3.java
 *
 * Description: 
 * @author   coti
 * @version   1.1
 */


import java.awt.Dimension;
import java.awt.Component;
import java.awt.Toolkit;
import java.awt.event.WindowAdapter;
import java.awt.event.WindowEvent;
import javax.swing.JComponent;
import javax.swing.JFrame;
import javax.swing.UIManager;

public class JFrame3 extends JFrame{
 Dimension dim_pantalla, dim_cuadro;
 int posx, posy;
 JFrame3(JComponent c) {
  super("Sin título");
  addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent we) {
    System.exit(0);
   }
  });
  try
   {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
   }
  catch(Exception e)
   {
    System.err.println(e);
   }
  getContentPane().add(c);
  dim_pantalla = Toolkit.getDefaultToolkit().getScreenSize();
  dim_cuadro = c.getPreferredSize();
  //if (c.getPreferredSize().width!=0)
  pack();
  setLocation( (dim_pantalla.width-dim_cuadro.width)/2,
      (dim_pantalla.height-dim_cuadro.height)/2);

  setVisible(true);
 } // Constructor sin tÌtulo
 
 JFrame3(String t, JComponent c) {
  super(t);
  addWindowListener(new WindowAdapter() {
   public void windowClosing(WindowEvent we) {
    System.exit(0);
   }
  });
  try
   {
    UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
   }
  catch(Exception e)
   {
    System.err.println(e);
   }
  getContentPane().add(c);
  dim_pantalla = Toolkit.getDefaultToolkit().getScreenSize();
  dim_cuadro = c.getPreferredSize();
  pack();
  setLocation( (dim_pantalla.width-dim_cuadro.width)/2,
      (dim_pantalla.height-dim_cuadro.height)/2);

  setVisible(true);
 } // Constructor con tÌtulo
}




JPanelBotones.java
import java.awt.Color;
import java.awt.Container;
import java.awt.GridLayout;
import java.awt.CardLayout;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import javax.swing.JButton;
import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class JPanelBotones extends JPanel implements ActionListener{
 JPanelDatos panel_datos;
 JPanelResultados panel_resultados;
 JButton datos,resultados;
 CardLayout disposicion;
 Container contenedor;
 JPanelBotones( JPanelDatos jpd,
     JPanelResultados jpr,
     CardLayout cl,
     Container cd) {
  panel_datos = jpd;
  panel_resultados = jpr;
  disposicion = cl;
  contenedor = cd;
  
  datos = new JButton("Ver datos");
  datos.setActionCommand(Dim.ACCION_DATOS+"");
  datos.addActionListener(this);
  
  resultados = new JButton("Ver resultados");
  resultados.setActionCommand(Dim.ACCION_RESULTADOS+"");
  resultados.addActionListener(this);
  
  setLayout(new GridLayout(1,2));
  
  add(datos);
  add(resultados);
 }
 public void actionPerformed(ActionEvent ae) {
  char accion = ae.getActionCommand().charAt(0);
  String st=null;
  switch (accion){
   case Dim.ACCION_DATOS:
     for(int i=0;i<Dim.FILAS;i++)
      for(int j=0;j<Dim.COLUMNAS;j++)
       {
        st = panel_datos.jta[i][j].getText();
        panel_datos.matriz_a[i][j]= (!st.equals(""))?Float.parseFloat(st):0.0f;
        panel_datos.jta[i][j].setText(panel_datos.matriz_a[i][j]+"");
        st = panel_datos.jtb[i][j].getText();
        panel_datos.matriz_b[i][j]= (!st.equals(""))?Float.parseFloat(st):0.0f;
        panel_datos.jtb[i][j].setText(panel_datos.matriz_b[i][j]+"");
       }
     // Mostrar panel de datos
     disposicion.show(contenedor, Dim.DATOS);
     break;
   case Dim.ACCION_RESULTADOS:
     // Leer información
     for(int i=0;i<Dim.FILAS;i++)
      for(int j=0;j<Dim.COLUMNAS;j++)
       {
        st = panel_datos.jta[i][j].getText();
        panel_datos.matriz_a[i][j]= (!st.equals(""))?Float.parseFloat(st):0.0f;
        panel_datos.jta[i][j].setText(panel_datos.matriz_a[i][j]+"");
        st = panel_datos.jtb[i][j].getText();
        panel_datos.matriz_b[i][j]= (!st.equals(""))?Float.parseFloat(st):0.0f;
        panel_datos.jtb[i][j].setText(panel_datos.matriz_b[i][j]+"");
       }
     // Calcular
     float temp;
     for(int i=0;i<Dim.FILAS;i++)
      for(int j=0;j<Dim.COLUMNAS;j++)
       {
        panel_resultados.suma[i][j]=panel_datos.matriz_a[i][j]+panel_datos.matriz_b[i][j];
        panel_resultados.resta[i][j]=panel_datos.matriz_a[i][j]-panel_datos.matriz_b[i][j];
       }
     for(int i=0;i<Dim.FILAS;i++)
      for(int j=0; j< Dim.COLUMNAS; j++)
       {
        temp =0.0f;
        for(int k=0;k<Dim.FILAS;k++)
         temp += panel_datos.matriz_a[i][k]*panel_datos.matriz_b[k][j];
        panel_resultados.multi[i][j] = temp;
       }
     // Mostrar resultados
     for(int i=0;i<Dim.FILAS;i++)
      for(int j=0;j<Dim.COLUMNAS;j++)
       {
        panel_resultados.jtsuma[i][j].setText(panel_resultados.suma[i][j]+"");
        panel_resultados.jtresta[i][j].setText(panel_resultados.resta[i][j]+"");
        panel_resultados.jtmulti[i][j].setText(panel_resultados.multi[i][j]+"");
       }
     disposicion.show(contenedor, Dim.RESULTADOS);
     break;
  } /* Fin del Switch */
 } /* Fin del actioinPerformed() */
}


JPanelDatos.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;

public class JPanelDatos extends JPanel {
 float[][] matriz_a = new float[Dim.FILAS][Dim.COLUMNAS];
 float[][] matriz_b = new float[Dim.FILAS][Dim.COLUMNAS];
 JPanel pa, pb;
 FloatTextField[][] jta, jtb;
 FloatTextField temp;
 JPanelDatos() {
  pa = new JPanel(new GridLayout(Dim.FILAS,Dim.COLUMNAS));
  pb = new JPanel(new GridLayout(Dim.FILAS,Dim.COLUMNAS));
  
  jta = new FloatTextField[Dim.FILAS][Dim.COLUMNAS];
  jtb = new FloatTextField[Dim.FILAS][Dim.COLUMNAS];
  
  LineBorder lb = new LineBorder(Color.red,2);
  TitledBorder tba = new TitledBorder(lb, "Matriz A");
  TitledBorder tbb = new TitledBorder(lb, "Matriz B");
  
  pa.setBorder(tba);
  pb.setBorder(tbb);
 
  for(int i=0; i<Dim.FILAS;i++)
   for(int j=0; j<Dim.COLUMNAS; j++)
    {
     matriz_a[i][j] = 0.0f;
     temp = new FloatTextField(10);
     temp.setText("0.0");


     pa.add(temp);
     jta[i][j]= temp;
     
     matriz_b[i][j] = 0.0f;
     temp = new FloatTextField(10);
     temp.setText("0.0");


     pb.add(temp);
     jtb[i][j]= temp;
    }
  add(pa);
  add(pb);
 } // Constructor

}



JPanelResultados.java
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.GridLayout;
import javax.swing.border.EmptyBorder;
import javax.swing.border.LineBorder;
import javax.swing.border.TitledBorder;

import javax.swing.JLabel;
import javax.swing.JPanel;
import javax.swing.JTextField;

public class JPanelResultados extends JPanel{
 float[][] suma,resta, multi;
 JTextField[][] jtsuma,jtresta, jtmulti;
 JTextField temp;
 JPanel psuma, presta,pmulti;
 JPanelResultados() {
  suma = new float[Dim.FILAS][Dim.COLUMNAS];
  resta = new float[Dim.FILAS][Dim.COLUMNAS];
  multi = new float[Dim.FILAS][Dim.COLUMNAS];
  
  jtsuma = new JTextField[Dim.FILAS][Dim.COLUMNAS];
  jtresta = new JTextField[Dim.FILAS][Dim.COLUMNAS];
  jtmulti = new JTextField[Dim.FILAS][Dim.COLUMNAS];
  
  psuma = new JPanel(new GridLayout(Dim.FILAS,Dim.COLUMNAS));
  presta = new JPanel(new GridLayout(Dim.FILAS,Dim.COLUMNAS));
  pmulti = new JPanel(new GridLayout(Dim.FILAS,Dim.COLUMNAS));
  for(int i=0; i<Dim.FILAS;i++)
   for(int j=0;j<Dim.COLUMNAS;j++)
    {
     suma[i][j]=0.0f;
     resta[i][j]=0.0f;
     multi[i][j]=0.0f;
     temp = new JTextField(Dim.ANCHURA_CAMPO);
     temp.setText("0.0");
     temp.setEditable(false);
     psuma.add(temp);
     jtsuma[i][j] = temp;
     temp = new JTextField(Dim.ANCHURA_CAMPO);
     temp.setText("0.0");
     temp.setEditable(false);
     presta.add(temp);
     jtresta[i][j] = temp;
     temp = new JTextField(Dim.ANCHURA_CAMPO);
     temp.setText("0.0");
     temp.setEditable(false);
     pmulti.add(temp);
     jtmulti[i][j] = temp;
    }
  LineBorder lb = new LineBorder(Color.red,2);
  TitledBorder tbsuma = new TitledBorder(lb, "Suma");
  TitledBorder tbresta = new TitledBorder(lb, "Resta");
  TitledBorder tbmulti = new TitledBorder(lb, "Multiplicación");
  psuma.setBorder(tbsuma);
  presta.setBorder(tbresta);
  pmulti.setBorder(tbmulti);
  add(psuma);
  add(presta);
  add(pmulti);

 }
}





Comentarios.- El aspecto que adopta este programa al ser ejecutado es el que puede verse en las imágenes. Se han instroducido como datos de prueba dos matrices sencillas, que hacen posible verificar manualmente la corrección de los cálculos. Evidentemente esto no es un conjunto de datos de prueba; sería preciso efectuar comprobaciones más extensas, llegando incluso a calcular manualmente los resultados correspondientes a dos matrices aleatorias. Esto puede hacer aparecer errores, que una vez corregidos aumentarán nuestra confianza en el producto. Pero téngase en cuenta que unos resultados correctos no constituyen prueba de correción en general.

Si se estudia la clase FloatTextField, se verá que el usuario puede tener confianza en que los posibles errores tipográficos serán detectados antes de llegar a insertar información que no tenga sentido dentro de un número de coma flotante. En otras palabras, se trata de un método de validación de datos, que se podrá emplear en otras ocasiones.