Skip to content

5. Interfaces gráficas

Aquí nos proponemos mostrar cómo construir interfaces gráficas con JAVA. En primer lugar, veremos cuáles son las clases básicas que nos permiten construir una interfaz gráfica. En un primer momento, no utilizaremos ninguna herramienta de generación automática. Luego utilizaremos JBuilder, una herramienta de desarrollo de Borland/Inprise que facilita el desarrollo de aplicaciones Java y, en particular, la construcción de interfaces gráficas.

5.1. Fundamentos de las interfaces gráficas

5.1.1. Una ventana simple

Consideremos el siguiente código:


// clases importadas
import javax.swing.*;
import java.awt.*;
    
    // la clase formulario
  public class form1 extends JFrame {
    
      // el constructor
      public form1() {
            // título de la ventana
            this.setTitle("Mon premier formulaire");
            // dimensiones de la ventana
            this.setSize(new Dimension(300,100));
      }//constructor
  
      // función de prueba
      public static void main(String[] args) {
            // se muestra el formulario
            new form1().setVisible(true);
      }
  }//clase

Al ejecutar el código anterior, aparece la siguiente ventana:

Image

Una interfaz gráfica suele derivarse de la clase base JFrame:


  public class form1 extends JFrame {

La clase base JFrame define una ventana básica con botones para cerrar, ampliar o reducir, un tamaño ajustable, etc., y maneja los eventos en estos objetos gráficos. Aquí especializamos la clase base asignándole un título y su ancho (300 píxeles) y alto (100 píxeles). Esto se hace en su constructor:


      // el constructor
      public form1() {
            // título de la ventana
            this.setTitle("Mon premier formulaire");
            // dimensiones de la ventana
            this.setSize(new Dimension(300,100));
      }//constructor

El título de la ventana se establece mediante el método setTitle y sus dimensiones mediante el método setSize. Este método acepta como parámetro un objeto Dimension(largeur,hauteur), donde largeur y hauteur son el ancho y la altura de la ventana, expresados en píxeles.

El método main inicia la aplicación gráfica de la siguiente manera:


            new form1().setVisible(true);

A continuación, se crea un formulario de tipo form1 (new form1()) y se muestra (setVisible(true)); luego, la aplicación comienza a escuchar los eventos que ocurren en el formulario (clics, movimientos del ratón, ...) y ejecuta aquellos que el formulario maneja. En este caso, nuestro formulario no maneja otros eventos más que los que maneja la clase base JFrame (clics en los botones de cierre, maximizar/minimizar, cambio de tamaño de la ventana, desplazamiento de la ventana, etc.).

Cuando se prueba este programa ejecutándolo desde una ventana de DOS mediante:

java form1

para ejecutar el archivo form1.class, se observa que al cerrar la ventana que se ha mostrado, no se «recupera el control» en la ventana de DOS, como si el programa no hubiera terminado. De hecho, así es. La ejecución del programa se realiza de la siguiente manera:

  • al inicio, se lanza un primer hilo de ejecución para ejecutar el método main
  • cuando este crea el formulario y lo muestra, se crea un segundo hilo para gestionar específicamente los eventos relacionados con el formulario
  • tras esta creación y, en nuestro ejemplo, el hilo del método main finaliza y solo queda entonces el hilo de ejecución de la interfaz gráfica.
  • Cuando se cierra la ventana, esta desaparece, pero no interrumpe el hilo en el que se estaba ejecutando
  • Por el momento, nos vemos obligados a detener este hilo presionando Ctrl-C en la ventana de DOS desde donde se inició la ejecución del programa.

Verifiquemos la existencia de dos hilos separados: uno en el que se ejecuta el método main y otro en el que se ejecuta la ventana gráfica:


// clases importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;

// la clase del formulario
 public class form1 extends JFrame {
    
// el constructor
 public form1() {
   // título de la ventana
   this.setTitle("Mon premier formulaire");
   // dimensiones de la ventana
   this.setSize(new Dimension(300,100));
}//constructor
  
// función de prueba
 public static void main(String[] args) {
   // seguimiento
   System.out.println("Début du thread main");
   // se muestra el formulario
   new form1().setVisible(true);
   // seguimiento
   System.out.println("Fin du thread main");  
}//principal
}//clase

La ejecución arroja los siguientes resultados:

Image

Se puede observar que el hilo main ha finalizado, mientras que la ventana sigue visible. El hecho de cerrar la ventana no detiene el hilo en el que se estaba ejecutando. Para detener este hilo, presionamos nuevamente Ctrl-C en la ventana de DOS.

Para concluir este ejemplo, tomemos nota de los paquetes importados:

  • javax.swing para la clase JFrame
  • java.awt para la clase Dimension

5.1.2. Manejar un evento

En el ejemplo anterior, tendríamos que gestionar el cierre de la ventana nosotros mismos para que, cuando ocurra, se detenga la aplicación, lo cual por el momento no se hace. Para ello, debemos crear un objeto que «escuche» los eventos que ocurren en la ventana y detecte el evento «cierre de la ventana». A este objeto se le llama «listener» o manejador de eventos. Existen diferentes tipos de manejadores para los distintos eventos que pueden ocurrir en los componentes de una interfaz gráfica. Para el componente JFrame, el listener se llama WindowListener y es una interfaz que define los siguientes métodos (véase la documentación de Java)

Resumen de métodos
 
void
windowActivated(WindowEvent e)
          La ventana se convierte en la ventana activa
 
void
windowClosed(WindowEvent e)
          La ventana se ha cerrado
 
void
windowClosing(WindowEvent e)
          El usuario o el programa solicitó el cierre de la ventana
 
void
windowDeactivated(WindowEvent e)
          La ventana ya no es la ventana activa
 
void
windowDeiconified(WindowEvent e)
          La ventana pasa del estado minimizado al estado normal
 
void
windowIconified(WindowEvent e)
          La ventana pasa del estado normal al estado minimizado
 
void
windowOpened(WindowEvent e)
          La ventana se vuelve visible por primera vez
 

Por lo tanto, hay siete eventos que se pueden manejar. Todos los manejadores reciben como parámetro un objeto de tipo WindowEvent que, por el momento, ignoramos. El evento que nos interesa aquí es el cierre de la ventana, evento que deberá ser procesado por el método windowClosing. Para manejar este evento, podemos crear un objeto Windowlistener utilizando una clase anónima de la siguiente manera:


   // creación de un administrador de eventos
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//definición de win

Nuestro administrador de eventos que implementa la interfaz WindowListener debe definir los siete métodos de esta interfaz. Como solo queremos gestionar el cierre de la ventana, solo definimos código para el método windowClosing. Cuando ocurran los demás eventos, se nos notificará, pero no haremos nada. ¿Qué haremos cuando se nos notifique que la ventana se está cerrando (windowClosing)? Detendremos la aplicación:


     public void windowClosing(WindowEvent e){System.exit(0);}

Aquí tenemos un objeto capaz de manejar los eventos de una ventana en general. ¿Cómo lo asociamos a una ventana específica? La clase JFrame cuenta con un método addWindowListener(WindowListener win) que permite asociar un manejador de eventos de «ventana» a una ventana específica. Así que aquí, en el constructor de la ventana, escribiremos:


   // creación de un administrador de eventos
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//definición de Windows
    // este gestor de eventos se encargará de gestionar los eventos de la ventana actual
   this.addWindowListener(win);

El programa completo es el siguiente:


// clases importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// la clase formulario
 public class form2 extends JFrame {
    
// el constructor
 public form2() {
   // título de la ventana
   this.setTitle("Mon premier formulaire");
   // dimensiones de la ventana
   this.setSize(new Dimension(300,100));
   // creación de un manejador de eventos
   WindowListener win=new WindowListener(){
     public void windowActivated(WindowEvent e){}
     public void windowClosed(WindowEvent e){}
     public void windowClosing(WindowEvent e){System.exit(0);}
     public void windowDeactivated(WindowEvent e){}
     public void windowDeiconified(WindowEvent e){}
     public void windowIconified(WindowEvent e){}
     public void windowOpened(WindowEvent e){}
   };//definición de Windows
   // este gestor de eventos manejará los eventos de la ventana actual
   this.addWindowListener(win);
}//constructor
  
// función de prueba
 public static void main(String[] args) {
   // se muestra el formulario
   new form2().setVisible(true);
}//main
}//clase

El paquete java.awt.event contiene la interfaz WindowListener. Al ejecutar este programa y cerrar la ventana que se ha mostrado, se observa en la ventana de DOS desde donde se lanzó el programa que este ha finalizado su ejecución, algo que antes no ocurría.

En nuestro programa, la creación del objeto encargado de manejar los eventos de la ventana resulta un poco engorrosa, ya que nos vemos obligados a definir métodos incluso para eventos que no queremos manejar. En este caso, en lugar de utilizar la interfaz WindowListener, se puede utilizar la clase WindowAdapter. Esta implementa la interfaz WindowListener, con siete métodos vacíos. Al derivar la clase WindowAdapter y redefinir únicamente los métodos que nos interesan, obtenemos el mismo resultado que con la interfaz WindowListener, pero sin necesidad de definir los métodos que no nos interesan. La secuencia

  • definición del manejador de eventos
  • asociar el manejador a la ventana

puede llevarse a cabo de la siguiente manera en nuestro ejemplo:


   // creación de un controlador de eventos
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//definición de win
   // este gestor de eventos manejará los eventos de la ventana actual
   this.addWindowListener(win);

Aquí utilizamos una clase anónima que deriva de la clase WindowAdapter y redefine su método windowClosing. El programa queda entonces así:


// clases importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// la clase formulario
 public class form2 extends JFrame {
    
// el constructor
 public form2() {
   // título de la ventana
   this.setTitle("Mon premier formulaire");
   // dimensiones de la ventana
   this.setSize(new Dimension(300,100));
   // creación de un manejador de eventos
   WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
   };//definición de Windows
   // este gestor de eventos manejará los eventos de la ventana actual
   this.addWindowListener(win); }//constructor
  
// función de prueba
 public static void main(String[] args) {
   // se muestra el formulario
   new form2().setVisible(true);
}//main
}//clase

Da los mismos resultados que el programa anterior, pero es más sencillo de escribir.

5.1.3. Un formulario con un botón

Ahora agreguemos un botón a nuestra ventana:


// clases importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// la clase formulario
 public class form3 extends JFrame {
 
     // un botón
  JButton btnTest=null;
  Container conteneur=null;
  
  // el constructor
  public form3() {
     // título de la ventana
    this.setTitle("Formulaire avec bouton");
     // dimensiones de la ventana
    this.setSize(new Dimension(300,100));
    // creación de un controlador de eventos
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definición de Windows
     // este gestor de eventos manejará los eventos de la ventana actual
    this.addWindowListener(win);
     // se recupera el contenedor de la ventana
    conteneur=this.getContentPane();
     // se elige un controlador de diseño de componentes en este contenedor
    conteneur.setLayout(new FlowLayout());
    // se crea un botón
    btnTest=new JButton();
    // se establece su texto
    btnTest.setText("Test");
    // se agrega el botón al contenedor
    conteneur.add(btnTest);
  }//constructor
  
  // función de prueba
 public static void main(String[] args) {
    // se muestra el formulario
   new form3().setVisible(true);
}//main
}//clase

Una ventana JFrame cuenta con un contenedor en el que se pueden colocar componentes gráficos (botones, casillas de selección, listas desplegables, etc.). Este contenedor está disponible a través del método getContentPane de la clase JFrame:


  Container conteneur=null;
..........
     // se recupera el contenedor de la ventana
    conteneur=this.getContentPane();

Cada componente se coloca en el contenedor mediante el método add de la clase Container. Por lo tanto, para colocar el componente C en el objeto conteneur anterior, se escribirá:

conteneur.add(C)

¿En qué parte del contenedor se coloca este componente? Existen varios administradores de disposición de componentes con el nombre XXXLayout, siendo XXX, por ejemplo, igual a Border, Flow, ... Cada gestor de disposición tiene sus propias características. Por ejemplo, el gestor FlowLayout dispone los componentes en filas, comenzando desde la parte superior del formulario. Cuando se completa una fila, los componentes se colocan en la siguiente fila. Para asociar un gestor de formato a una ventana JFrame, se utiliza el método setLayout de la clase JFrame de la siguiente forma:

    setLayout(objet XXXLayout);

Así, en nuestro ejemplo, para asociar un controlador de tipo FlowLayout a la ventana, escribimos:


     // se selecciona un administrador de formato para los componentes en este contenedor
    conteneur.setLayout(new FlowLayout());

Se puede optar por no utilizar un controlador de diseño y escribir:

    setLayout(null);

En este caso, habrá que indicar las coordenadas precisas del componente dentro del contenedor en el formato (x, y, ancho, alto), donde (x, y) son las coordenadas de la esquina superior izquierda del componente dentro del contenedor. Este es el método que utilizaremos con mayor frecuencia en lo sucesivo.

Ahora sabemos cómo se colocan los componentes en el contenedor (add) y dónde (setLayout). Nos queda por conocer los

componentes que se pueden colocar en un contenedor. Aquí colocamos un botón modelado por la clase javax.swing.JButton:



  JButton btnTest=null;
..........
     // se crea un botón
    btnTest=new JButton();
    // se establece su texto
    btnTest.setText("Test");
    // se agrega el botón al contenedor
    conteneur.add(btnTest);

Al ejecutar este programa, aparece la siguiente ventana:

Image

Si se cambia el tamaño del formulario anterior, se invoca automáticamente el administrador de diseño del contenedor para reubicar los componentes:

Image

Este es el principal interés de los administradores de diseño: mantener una disposición coherente de los componentes a medida que cambia el tamaño del contenedor. Usemos el administrador de diseño null para ver la diferencia. El botón ahora se coloca en el contenedor mediante las siguientes instrucciones:


// se selecciona un administrador de formato de componentes en este contenedor
conteneur.setLayout(null);
    // se crea un botón
btnTest=new JButton();
    // se establece su texto
btnTest.setText("Test");
    // se establece su ubicación y sus dimensiones
btnTest.setBounds(10,20,100,20);
     // se agrega el botón al contenedor
conteneur.add(btnTest);

Aquí colocamos explícitamente el botón en el punto (10,20) del formulario y establecemos sus dimensiones en 100 píxeles de ancho y 20 píxeles de alto. La nueva ventana queda así:

Image

Si cambiamos el tamaño de la ventana, el botón permanece en el mismo lugar.

Image

Si hacemos clic en el botón Test, no pasa nada. De hecho, aún no hemos asociado un manejador de eventos al botón. Para conocer el tipo de manejadores de eventos disponibles para un componente determinado, se puede buscar en la definición de su clase los métodos addXXXListener que permiten asociar un manejador de eventos al componente. La clase javax.swing.JButton deriva de la clase javax.swing.AbstractButton, en la que se encuentran los siguientes métodos:

Resumen de métodos
 
void
addActionListener(ActionListener l)
 
void
addChangeListener(ChangeListener l)
 
void
addItemListener(ItemListener l)
 

Aquí hay que consultar la documentación para saber qué controlador de eventos maneja el clic en el botón. Se trata de la interfaz ActionListener. Esta solo define un método:

Resumen de métodos
 
void
actionPerformed(ActionEvent e)
 

El método recibe un parámetro ActionEvent que ignoraremos por el momento. Para manejar el clic en el botón btntest de nuestro programa, primero le asignamos un manejador de eventos:


        btnTest.addActionListener(new ActionListener()
         {
                public void actionPerformed(ActionEvent evt){
                  btnTest_clic(evt);
              }
            }//clase anónima
    );//gestor de eventos

Aquí, el método actionPerformed hace referencia al método btnTest_clic, que definimos de la siguiente manera:


public void btnTest_clic(ActionEvent evt){
  // seguimiento de la consola
System.out.println("clic sur bouton");
}//btnTest_click

Cada vez que el usuario hace clic en el botón Test, se escribe un mensaje en la consola. Esto es lo que muestra la siguiente ejecución:

Image

El programa completo es el siguiente:


// clases importadas
import javax.swing.*;
import java.awt.*;
import java.io.*;
import java.awt.event.*;

// la clase formulario
 public class form4 extends JFrame {
 
     // un botón
  JButton btnTest=null;
  Container conteneur=null;
  
  // el constructor
  public form4() {
     // título de la ventana
    this.setTitle("Formulaire avec bouton");
     // dimensiones de la ventana
    this.setSize(new Dimension(300,100));
    // creación de un manejador de eventos
    WindowAdapter win=new WindowAdapter(){
     public void windowClosing(WindowEvent e){System.exit(0);}
    };//definición de Windows
     // este manejador de eventos gestionará los eventos de la ventana actual
    this.addWindowListener(win);
     // se recupera el contenedor de la ventana
    conteneur=this.getContentPane();
     // se elige un controlador de diseño de componentes en este contenedor
    conteneur.setLayout(null);
    // se crea un botón
    btnTest=new JButton();
    // se establece su texto
    btnTest.setText("Test");
    // se establece su ubicación y sus dimensiones
    btnTest.setBounds(10,20,100,20);
     // se le asocia un manejador de eventos
    btnTest.addActionListener(new ActionListener()
        {
            public void actionPerformed(ActionEvent evt){
              btnTest_clic(evt);
          }
        }//clase anónima
    );//manejador de eventos
     // se agrega el botón al contenedor
    conteneur.add(btnTest);
  }//constructor

    public void btnTest_clic(ActionEvent evt){
       // seguimiento de consola
    System.out.println("clic sur bouton");
  }//btnTest_click
    
  // función de prueba
 public static void main(String[] args) {
    // se muestra el formulario
   new form4().setVisible(true);
}//principal
}//clase

5.1.4. Los controladores de eventos

Los principales componentes de Swing que vamos a presentar son las ventanas (JFrame), los botones (JButton), las casillas de selección (JCheckBox), los botones de opción (JButtonRadio), las listas desplegables (JComboBox), las listas (JList), los controles deslizantes (JScrollBar), las etiquetas (JLabel), los campos de entrada de una línea (JTextField) o de varias líneas (JTextArea), los menús (JMenuBar), los elementos de menú (JMenuItem).

Las siguientes tablas presentan una lista de algunos controladores de eventos y los eventos a los que están vinculados.

Manejador
Componente(s)
Método de registro
Evento
ActionListener
JButton, JCheckbox, JButtonRadio, JMenuItem
public void addActionListener(ActionListener)
clic en el botón, la casilla de selección, el botón de opción, el elemento de menú
 
JTextField
ItemListener
JComboBox, JList
public void addItemListener(ItemListener)
El elemento seleccionado ha cambiado
InputMethodListener
JTextField, JTextArea
public void addMethodInputListener(InputMethodListener)
El texto del campo de entrada ha cambiado o el cursor de entrada ha cambiado de posición
CaretListener
JTextField, JTextArea
public void addcaretListener(CaretListener)
El cursor de entrada ha cambiado de posición
AdjustmentListener
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
El valor del variador ha cambiado
MouseMotionListener
 
public void addMouseMotionListener(MouseMotionListener)
el ratón se ha movido
WindowListener
JFrame
public void addWindowlistener(WindowListener)
evento de ventana
MouseListener
 
public void addMouselistener(MouseListener)
eventos del ratón (clic, entrada/salida del área de un componente, botón presionado, liberación)
FocusListener
 
public void addFocuslistener(FocusListener)
evento focus (obtenido, perdido)
KeyListener
 
public void addKeylistener(KeyListener)
evento de teclado (tecla pulsada, presionada, soltada)
Componente
Método para registrar los controladores de eventos
JButton
public void addActionListener(ActionListener)
JCheckbox
public void addItemListener(ItemListener)
JCheckboxMenuItem
public void addItemListener(ItemListener)
JComboBox
public void addItemListener(ItemListener)
public void addActionListener(ActionListener)
Container
public void addContainerListener(ContainerListener)
JComponent
public void addComponentListener(ComponentListener)
public void addFocusListener(FocusListener)
public void addKeyListener(KeyListener)
public void addMouseListener(MouseListener)
public void addMouseMotionListener(MouseMotionListener)
JFrame
public void addWindowlistener(WindowListener)
JList
public void addItemListener(ItemListener)
JMenuItem
public void addActionListener(ActionListener)
JPanel
como contenedor
JScrollPane
como contenedor
JScrollBar
public void addAdjustmentListener(AdjustmentListener)
JTextComponent
public void addInputMethodListener(InputMethodListener)
public void addCaretListener(CaretListener)
JTextArea
comme JTextComponent
JTextField
como JTextComponent
public void addActionListener(ActionListener)

Todos los componentes, excepto los del tipo TextXXX, al derivarse de la clase JComponent, también cuentan con los métodos asociados a dicha clase.

5.1.5. Los métodos de los controladores de eventos

La siguiente tabla enumera los métodos que deben implementar los distintos manejadores de eventos.

Interfaz
Métodos
ActionListener
public void actionPerformed(ActionEvent)
AdjustmentListener
public void adjustmentValueChanged(AdjustmentEvent)
ComponentListener
public void componentHidden(ComponentEvent)
public void componentMoved(ComponentEvent)
public void componentResized(ComponentEvent)
public void componentShown(ComponentEvent)
ContainerListener
public void componentAdded(ContainerEvent)
public void componentRemoved(ContainerEvent)
FocusListener
public void focusGained(FocusEvent)
public void focusLost(FocusEvent)
ItemListener
public void itemStateChanged(ItemEvent)
KeyListener
public void keyPressed(KeyEvent)
public void keyReleased(KeyEvent)
public void keyTyped(KeyEvent)
MouseListener
public void mouseClicked(MouseEvent)
public void mouseEntered(MouseEvent)
public void mouseExited(MouseEvent)
public void mousePressed(MouseEvent)
public void mouseReleased(MouseEvent)
MouseMotionListener
public void mouseDragged(MouseEvent)
public void mouseMoved(MouseEvent)
TextListener
public void textValueChanged(TextEvent)
InputmethodListener
public void InputMethodTextChanged(InputMethodEvent)
public void caretPositionChanged(InputMethodEvent)
CaretLisetner
public void caretUpdate(CaretEvent)
WindowListener
public void windowActivated(WindowEvent)
public void windowClosed(WindowEvent)
public void windowClosing(WindowEvent)
public void windowDeactivated(WindowEvent)
public void windowDeiconified(WindowEvent)
public void windowIconified(WindowEvent)
public void windowOpened(WindowEvent)

5.1.6. Las clases adaptadoras

Como hemos visto con la interfaz WindowListener, existen clases denominadas XXXAdapter que implementan las interfaces XXXListener con métodos vacíos. Un manejador de eventos derivado de una clase XXXAdapter puede, entonces, implementar solo una parte de los métodos de la interfaz XXXListener, aquellos que la aplicación necesita.

Supongamos que queremos gestionar los clics del ratón en un componente Frame f1. Podríamos asociarle un manejador de eventos mediante:

    f1.addMouseListener(new gestionnaireSouris());

y escribir:


    public class gestionnaireSouris implements MouseListener{
         // se escriben los 5 métodos de la interfaz MouseListener
        // mouseClicked, ..., mouseReleased)
    }// fin de clase

Sin embargo, como solo queremos manejar los clics del ratón, es preferible escribir:


public class gestionnaireSouris extends MouseAdapter{
        // se escribe un solo método, el que maneja los clics del ratón
        public void mouseClicked(MouseEvent evt){

        }
}// fin de clase

La siguiente tabla muestra las clases adaptadoras de los distintos administradores de eventos:

Manejador de eventos
Adaptador
ComponentListener
ComponentAdapter
ContainerListener
ContainerAdapter
FocusListener
FocusAdapter
KeyListener
KeyAdapter
MouseListener
MouseAdapter
MouseMotionListener
MouseMotionAdapter
WindowListener
WindowAdapter

5.1.7. Conclusión

Acabamos de presentar los conceptos básicos de la creación de interfaces gráficas en Java:

  • creación de una ventana
  • creación de componentes
  • asignación de componentes a la ventana mediante un gestor de diseño
  • asignación de manejadores de eventos a los componentes

Ahora, en lugar de construir interfaces gráficas «a mano» como acabamos de hacerlo, utilizaremos JBuilder, una herramienta de desarrollo de Java de Borland/Inprise en su versión 4, y supérieure.Nous utilizaremos los componentes de la biblioteca java.swing, recomendada actualmente por Sun, creador de Java.

5.2. Crear una interfaz gráfica con JBuilder

5.2.1. Nuestro primer proyecto con JBuilder

Para familiarizarnos con JBuilder, vamos a crear una aplicación muy sencilla: una ventana vacía.

  1. Inicia JBuilder y selecciona la opción Archivo/Nuevo proyecto. A continuación, aparecerá la primera página de un asistente:

Image

  1. Llena los siguientes campos:
Nombre del proyecto
Inicio
Esto generará un archivo de proyecto début.jpr en la carpeta indicada en el campo «Nombre del directorio del proyecto»
Ruta raíz
Indique la carpeta en la que se creará la carpeta del proyecto que va a crear.
Nombre del directorio del proyecto
Indica el nombre de la carpeta donde se colocarán todos los archivos del proyecto. Esta carpeta se creará en el directorio indicado en el campo «Ruta raíz»

Los archivos de origen (.java, .html, ...), los archivos de destino (.class, ...) y los archivos de respaldo podrían ir en directorios diferentes. Si deja sus campos en blanco, se colocarán en el mismo directorio que el proyecto.

Escriba [suivant]

  1. Una pantalla confirma las opciones seleccionadas en el paso anterior

Image

Seleccione [suivant]

  1. Aparece una nueva pantalla que le pide que defina su proyecto:

Image

Seleccione [terminer]

  1. Verifique que la opción Voir/projet esté marcada. Debería ver la estructura de su proyecto en la ventana de la izquierda.

Image

  1. Ahora construyamos una interfaz gráfica en este proyecto. Seleccione la opción Fichier/Nouveau/Application:

Image

En el campo classe, se ingresa el nombre de la clase que se va a crear. Aquí hemos utilizado el mismo nombre que el del proyecto.

Ejecute [suivant]

  1. Aparecerá la siguiente pantalla:

Image

Clase
interfaceDébut
Este es el nombre de la clase correspondiente a la ventana que se va a crear
Título
Es el texto que aparecerá en la barra de título de la ventana

Tenga en cuenta que, en el ejemplo anterior, hemos indicado que la ventana se centre en la pantalla al iniciar la aplicación.

Escriba [Terminer]

  1. Ahora es cuando JBuilder resulta útil.
  • Genera los archivos fuente .java de las dos clases cuyos nombres hemos indicado: la clase de la aplicación y la de la interfaz gráfica. Estos dos archivos aparecen en la estructura del proyecto en la ventana de la izquierda

Image

  • Para acceder al código generado para ambas clases, basta con hacer doble clic en el archivo .java correspondiente. Volveremos más adelante al código generado.
  • Verifica que la opción Voir/Structure esté marcada. Esta opción permite ver la estructura de la clase seleccionada actualmente (al hacer doble clic en el archivo .java). A continuación se muestra, por ejemplo, la estructura de la clase début:

Image

Aquí se puede ver:

  • las bibliotecas importadas (imports)

  • que hay un constructor début()

  • que hay un método estático main()

  • que hay un atributo packFrame

¿Cuál es la ventaja de tener acceso a la estructura de una clase?

  • Te da una visión general de la misma. Esto es útil si tu clase es compleja.

  • puedes acceder al código de un método al hacer clic en él en la ventana de estructura de la clase. De nuevo, esto es útil si tu clase tiene cientos de líneas. No tienes que revisar todas las líneas para encontrar el código que buscas.

El código generado por JBuilder ya está listo para usarse. Selecciona Ejecutar/Ejecutar el proyecto o F9 y aparecerá la ventana solicitada:

Image

Además, se cierra correctamente al hacer clic en el botón de cierre de la ventana. Acabamos de crear nuestra primera interfaz gráfica. Podemos guardar nuestro proyecto mediante la opción Archivo/Cerrar proyectos:

Image

Al presionar Tous, se marcarán todos los proyectos que aparecen en la ventana anterior. OK los cerrará. Si tenemos curiosidad por ir, con el Explorador de Windows, a la carpeta de nuestro proyecto (la que se le indicó al asistente al inicio de la configuración del proyecto), encontraremos allí los siguientes archivos:

Image

En nuestro ejemplo, habíamos solicitado que todos los archivos (fuente .java, destino .class, copia de seguridad .jpr~) estuvieran en la misma carpeta que el proyecto .jpr.

5.2.2. Los archivos generados por JBuilder para una interfaz gráfica

Ahora, veamos qué archivos fuente .java ha generado JBuilder. Es importante saber interpretar lo que se genera, ya que la mayoría de las veces tendremos que agregar código a lo que se ha generado. Comencemos por abrir nuestro proyecto: Archivo/Abrir un proyecto y seleccionemos el proyecto début.jpr. Encontramos el proyecto creado anteriormente.

5.2.2.1. La clase principal

Examinemos la clase début.java haciendo doble clic en su nombre en la ventana que muestra la lista de archivos del proyecto. Tenemos el siguiente código:

import javax.swing.UIManager;
import java.awt.*;

public class début {
  boolean packFrame = false;

   /**Compilar la aplicación*/
  public début() {
    interfaceDébut frame = new interfaceDébut();

     //Validar los marcos con tamaños predefinidos
     //Ajustar los marcos con información de tamaño preferido por ejemplo, según su disposición
    if (packFrame) {
      frame.pack();
    }
    else {
      frame.validate();
    }
    //Centrar la ventana
    Dimension screenSize = Toolkit.getDefaultToolkit().getScreenSize();
    Dimension frameSize = frame.getSize();
    if (frameSize.height > screenSize.height) {
      frameSize.height = screenSize.height;
    }
    if (frameSize.width > screenSize.width) {
      frameSize.width = screenSize.width;
    }
    frame.setLocation((screenSize.width - frameSize.width) / 2, (screenSize.height - frameSize.height) / 2);
    frame.setVisible(true);
  }
   /**Método principal*/
  public static void main(String[] args) {
    try {
      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());
    }
    catch(Exception e) {
      e.printStackTrace();
    }
    new début();
  }
}

Comentemos el código generado:

  1. la función main define el aspecto de la ventana (setLookAndFeel) y crea una instancia de la clase début.
  2. A continuación, se ejecuta el constructor début(). Este crea una instancia frame de la clase de la ventana (new interfaceDébut()). Esta instancia se construye, pero no se muestra.
  3. A continuación, la ventana se dimensiona según la información disponible para cada uno de sus componentes (frame.validate). Entonces comienza su existencia independiente al mostrarse y responder a las solicitudes del usuario.
  4. La ventana se centra en la pantalla porque así se solicitó al configurarla con el asistente.

Veamos qué se obtendría si redujéramos el código début.java a lo estrictamente necesario, tal como lo hicimos al inicio del capítulo. Creemos una nueva clase. Seleccione la opción Archivo/Nueva clase:

Image

Nombra la nueva clase début2 y cambia [Terminer]. Aparece un nuevo archivo en el proyecto:

Image

El archivo début2.java se reduce a su forma más simple:

public class début2 {
}

Completemos la clase de la siguiente manera:

public class début2 {
   // función principal
  public static void main(String args[]){
    // crea la ventana
    new interfaceDébut().show();    // o new interfaceDébut.setVisible(true);
  }//main
}//clase inicio2

La función main crea una instancia de la ventana interfaceDébut y la muestra (show). Antes de ejecutar nuestro proyecto, debemos señalar que la clase que contiene la función main que se va a ejecutar es ahora la clase début2. Haz clic con el botón derecho del ratón en el proyecto début.jpr y selecciona la opción propriétés, luego la pestaña Exécution:

21

Image

Aquí se indica que la clase principal es début (1). Presiona el botón (2) para seleccionar otra clase principal:

Image

Seleccione début2 y cambie [OK].

Image

Seleccione [OK] para confirmar esta elección y luego solicite la ejecución del proyecto mediante Ejecutar/Ejecutar proyecto o F9. Aparecerá la misma ventana que con la clase début, salvo que no está centrada, ya que en este caso no se ha solicitado. A partir de ahora, ya no presentaremos la clase principal generada por JBuilder, ya que siempre hace lo mismo: crear una ventana. De ahora en adelante, nos centraremos en la clase de esta última.

5.2.2.2. La clase de la ventana

Veamos ahora el código que se generó para la clase interfaceDébut:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceDébut extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

  /**Construir el marco*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
}

5.2.2.2.1. Las bibliotecas importadas
import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

Se trata de las bibliotecas java.awt, java.awt.event y javax.swing. Las dos primeras eran las únicas disponibles para crear interfaces gráficas con las primeras versiones de Java. La biblioteca javax.swing es más reciente. En este caso, es necesaria para la ventana de tipo JFrame que se utiliza aquí.

5.2.2.2.2. Los atributos
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();

JPanel es un tipo de contenedor en el que se pueden colocar componentes. BorderLayout es uno de los tipos de administradores de diseño disponibles para colocar los componentes en el contenedor. En todos nuestros ejemplos, no utilizaremos ningún gestor de formato y colocaremos nosotros mismos los componentes en un lugar específico del contenedor. Para ello, utilizaremos el gestor de formato null.

5.2.2.2.3. El generador de la ventana
   /**Construir el marco*/
  public interfaceDébut() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(borderLayout1);
    this.setSize(new Dimension(400, 300));
    this.setTitle("Ma première interface graphique avec Jbuilder");
  }
  1. El desarrollador comienza diciendo que va a manejar los eventos en la ventana (enableEvents), y luego ejecuta el método jbInit.
  2. Se obtiene (getContentPane) el contenedor (JPanel) de la ventana (JFrame)
  3. Se establece el administrador de formato (setLayout)
  4. Se establece el tamaño de la ventana (setSize)
  5. Se establece el título de la ventana (setTitle)

5.2.2.2.4. El administrador de eventos
   /**Reemplazado, para que podamos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }

El desarrollador había indicado que la clase manejaría los eventos de la ventana. El método processWindowEvent es el encargado de realizar esta tarea. Comienza por transmitir a su clase padre (JFrame) el evento WindowEvent recibido y, si este es el evento WINDOW_CLOSING provocado al hacer clic en el botón de cierre de la ventana, la aplicación se detiene.

5.2.2.2.5. Conclusión

El código de la clase de la ventana es diferente al presentado en el ejemplo del inicio del capítulo. Si utilizáramos otra herramienta de generación de código Java distinta a JBuilder, sin duda tendríamos un código aún más diferente. En la práctica, aceptaremos el código generado por JBuilder para construir la ventana, a fin de concentrarnos únicamente en escribir los controladores de eventos de la interfaz gráfica.

5.2.3. Diseñar una interfaz gráfica

5.2.3.1. Un ejemplo

En el ejemplo anterior, no habíamos colocado ningún componente en la ventana. Ahora construyamos una ventana con un botón, un texto de etiqueta y un campo de entrada:

Image

Los campos son los siguientes:

n.º
nombre
tipo
función
1
lblSaisie
JLabel
una descripción
2
txtSaisie
JTextField
un campo de entrada
3
cmdAfficher
JButton
para mostrar en un cuadro de diálogo el contenido del campo de entrada txtSaisie

Siguiendo los mismos pasos que en el proyecto anterior, cree el proyecto interface2.jpr sin agregar por el momento ningún componente a la ventana.

Image

En la ventana anterior, seleccione la clase interface2.java de la ventana. A la derecha de esta ventana, hay un organizador con pestañas:

Image

La pestaña Source da acceso al código fuente de la clase interface2.java. La pestaña Conception permite construir visualmente la ventana. Seleccione esta pestaña. Tiene ante sí el contenedor de la ventana, que recibirá los componentes que vaya a colocar en él. Por el momento está vacío. En la ventana de la izquierda se muestra la estructura de la clase:

Image

this
representa la ventana
contentPane
su contenedor, en el que se colocarán los componentes, así como la forma en que se dispondrán dichos componentes dentro del contenedor (BorderLayout por defecto)
borderLayout1
una instancia del administrador de formato

Seleccione el objeto this. A continuación, aparecerá su ventana de propiedades a la derecha:

Image

Cabe destacar algunas de estas propiedades:

background
para establecer el color de fondo de la ventana
foreground
para establecer el color de los elementos gráficos en la ventana
JMenuBar
para asociar un menú a la ventana
title
para asignar un título a la ventana
resizable
para establecer el tipo de ventana
font
para establecer el tipo de letra del texto en la ventana

Con el objeto this aún seleccionado, se puede cambiar el tamaño del contenedor que se muestra en la pantalla arrastrando los puntos de anclaje situados alrededor del contenedor:

Image

Ahora estamos listos para colocar componentes en el contenedor anterior. Antes de eso, cambiaremos el administrador de formato. Seleccione el objeto contentPane en la ventana de estructura:

Image

Luego, en la ventana de propiedades de este objeto, seleccione la propiedad layout y elija, entre los valores posibles, el valor null:

Image

La ausencia de un administrador de formato nos permitirá colocar libremente los componentes en el contenedor. Ahora es el momento de seleccionarlos.

Cuando se selecciona el panel Conception, los componentes están disponibles en un organizador con pestañas en la parte superior de la ventana de diseño:

Image

Para construir la interfaz gráfica, contamos con los componentes swing (1) y los componentes awt (2). Aquí utilizaremos los componentes swing. En la barra de componentes de arriba, selecciona un componente JLabel (3), un componente JTextField (4) y un componente JButton (5), y colócalos en el contenedor de la ventana de diseño.

Image

Ahora personalicemos cada uno de estos tres componentes:

  • la etiqueta (JLabel) jLabel1

Seleccione el componente para abrir su ventana de propiedades. En ella, modifique las siguientes propiedades: nombre: lblSaisie, texto: Ingresar

  • el campo de entrada (JTextField) jTextfield1

Seleccione el componente para abrir su ventana de propiedades. En ella, modifique las siguientes propiedades: nombre: txtSaisie, texto: no ingrese nada

  • el botón (JButton): nombre: cmdAfficher, texto: Mostrar

Ahora tenemos la siguiente ventana:

Image

y la siguiente estructura:

Image

Podemos ejecutar (F9) nuestro proyecto para tener una primera vista previa de la ventana en acción:

Image

Cierra la ventana. Ahora nos queda escribir el procedimiento asociado al clic en el botón Afficher. Selecciona el botón para acceder a su ventana de propiedades. Esta tiene dos pestañas: propriétés y événements. Seleccione événements.

Image

La columna de la izquierda de la ventana muestra los eventos posibles para el botón. Al hacer clic en un botón se produce el evento actionPerformed. La columna de la derecha contiene el nombre del procedimiento que se invoca cuando ocurre el evento correspondiente. Haz clic en la celda a la derecha del evento actionPerformed:

Image

JBuilder genera un nombre predeterminado para cada controlador de eventos con el formato nomComposant_nomEvénement; en este caso, cmdAfficher_actionPerformed. Se podría borrar el nombre predeterminado y escribir otro. Para acceder al código del manejador cmdAfficher_actionPerformed, basta con hacer doble clic en su nombre arriba. De esta manera, se pasa automáticamente al panel de código fuente de la clase, donde se muestra el esqueleto del código del manejador de eventos:

  void cmdAfficher_actionPerformed(ActionEvent e) {
 }

Ahora solo nos queda completar este código. En este caso, queremos mostrar un cuadro de diálogo con el contenido del campo txtSaisie:

  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), 
"Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
 }

JOptionPane es una clase de la biblioteca javax.swing. Permite mostrar mensajes acompañados de un ícono o solicitar información al usuario. Aquí utilizamos un método estático de la clase:

Image

parentComponent
el objeto contenedor «padre» del cuadro de diálogo: en este caso, this.
mensaje
un objeto que se va a mostrar. En este caso, el contenido del campo de entrada
título
el título del cuadro de diálogo
messageType
el tipo de mensaje que se mostrará. Determina el ícono que aparecerá en el cuadro junto al mensaje. Los valores posibles son:
INFORMATION_MESSAGE, QUESTION_MESSAGE, ERROR_MESSAGE, WARNING_MESSAGE, PLAIN_MESSAGE

Ejecutemos nuestra aplicación (F9):

Image

Image

5.2.3.2. El código de la clase de la ventana

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import java.beans.*;
import javax.swing.event.*;


public class interface2 extends JFrame {
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

  /**Crear el marco*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }
   /**Reemplazado, para que podamos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }
}

5.2.3.2.1. Los atributos
  JPanel contentPane;
  JLabel lblSaisie = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmdAfficher = new JButton();

Se encuentra el contenedor de los componentes del tipo JPanel y los tres componentes.

5.2.3.2.2. El fabricante
   /**Crear el marco*/
  public interface2() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }

El constructor interface2 es similar al constructor de la interfaz gráfica anterior que analizamos. Las diferencias se encuentran en el método jbInit: el código de construcción de la ventana depende de los componentes que se hayan colocado en ella. Podemos retomar el código de jbInit y agregarle nuestros propios comentarios:

  private void jbInit() throws Exception  {
       // la ventana en sí (tamaño, título)
this.setSize(new Dimension(304, 129));
    this.setTitle("Saisies & boutons - 1");
         // el contenedor de los componentes
    contentPane = (JPanel) this.getContentPane();
         // no hay un administrador de formato para este contenedor
    contentPane.setLayout(null);
         // la etiqueta lblSaisie (texto, posición, tamaño)
         lblSaisie.setText("Saisie");
    lblSaisie.setBounds(new Rectangle(25, 23, 71, 21));
        // el campo de entrada (posición, tamaño)
    txtSaisie.setBounds(new Rectangle(120, 21, 138, 24));
         // el botón Mostrar (texto, posición, tamaño)
    cmdAfficher.setText("Afficher");
    cmdAfficher.setBounds(new Rectangle(111, 77, 77, 20));
         // el controlador de eventos del botón
    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
         // Agregación de los 3 componentes al contenedor
    contentPane.add(lblSaisie, null);
    contentPane.add(txtSaisie, null);
    contentPane.add(cmdAfficher, null);
  }//jbInit

Cabe destacar dos puntos:

  • este código podría haberse escrito a mano. Esto significa que no es necesario usar JBuilder para crear una interfaz gráfica.
  • la forma en que se configura el manejador de eventos del botón cmdAfficher. El manejador de eventos del componente cmdAfficher podría haberse declarado mediante cmdAfficher.addActionListener(new manejador()) donde gestionnaire sería una clase con un método público actionPerformed encargado de manejar el clic en el botón Afficher. Aquí, JBuilder utiliza como manejador una instancia de una clase anónima:
 new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }

Se crea una nueva instancia de la interfaz ActionListener y, al mismo tiempo, se define su método actionPerformed. Este método simplemente llama a un método de la clase interface2. Todo esto no es más que un recurso para definir, en la misma clase que la ventana, los procedimientos de manejo de eventos de los componentes de dicha ventana. Se podría proceder de otra manera:

cmdAfficher.addActionListener(this)

lo que hace que el método actionPerformed se busque en this, es decir, en la clase de la ventana. Este segundo método parece más sencillo, pero el primero tiene una ventaja: permite tener diferentes manejadores para diferentes botones, mientras que el segundo método no lo permite. En este último caso, de hecho, el único método actionPeformed debe procesar los clics de diferentes botones y, por lo tanto, debe comenzar por identificar cuál es el origen del evento antes de empezar a funcionar.

5.2.3.2.3. Los manejadores de eventos

Encontramos los que ya hemos estudiado:

   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
    super.processWindowEvent(e);
    if (e.getID() == WindowEvent.WINDOW_CLOSING) {
      System.exit(0);
    }
  }

     // clic en el botón Mostrar
  void cmdAfficher_actionPerformed(ActionEvent e) {
    JOptionPane.showMessageDialog(this, "texte saisi="+txtSaisie.getText(), "Vérification de la saisie",JOptionPane.INFORMATION_MESSAGE);
  }

5.2.3.3. Conclusion

A partir de los dos proyectos analizados, podemos concluir que, una vez construida la interfaz gráfica con JBuilder, el trabajo del desarrollador consiste en escribir los controladores de eventos que desea gestionar para dicha interfaz gráfica.

5.2.4. Buscar ayuda

Con Java, a menudo se necesita ayuda, sobre todo debido a la gran cantidad de clases disponibles. A continuación ofrecemos algunas indicaciones para encontrar ayuda sobre una clase. Seleccione la opción Ayuda/Temas de ayuda del menú.

Image

La pantalla de ayuda suele tener dos ventanas:

  • la de la izquierda, donde se indica lo que se busca. Cuenta con tres pestañas: Sommaire, Index y Chercher.
  • la de la derecha, que muestra el resultado de la búsqueda

Hay ayuda disponible sobre cómo usar la ayuda de JBuilder. Selecciona en la ayuda de JBuilder la opción Ayuda/Uso de la ayuda. Allí se te explicará cómo usar la ayuda. Por ejemplo, se te mostrarán los diferentes componentes del visor de ayuda:

Image

Analicemos con más detalle las páginas Sommaire y Index.

5.2.4.1. Ayuda: Índice

Image

5.2.4.1.1. Índice: Introducción a Java

Aquí se presentan los conceptos básicos de Java, pero no solo eso, como lo muestra la lista de temas que se abordan en esta opción:

Image

5.2.4.1.2. Índice: Tutoriales

Si seleccionamos la opción Tutoriales en el índice anterior, la ventana de la derecha nos muestra una lista de los tutoriales disponibles:

Image

Los tutoriales básicos son particularmente interesantes para empezar a familiarizarse con JBuilder. Existen muchos otros además de los presentados anteriormente y, cuando se desea desarrollar una aplicación, puede ser útil verificar primero si hay algún tutorial que pueda ayudarnos.

5.2.4.1.3. Índice: el JDK

Al seleccionar la opción Java 2 JDK 1.3, se tiene acceso a todas las bibliotecas de JDK. Por lo general, no es aquí donde hay que buscar si necesitamos información sobre una clase específica y no sabemos en qué biblioteca se encuentra. Sin embargo, esta opción resulta útil si nos interesa tener una visión general de las bibliotecas de Java.

5.2.4.2. Ayuda: Índice

Seleccione la pestaña Índice de la ventana de la izquierda en la ayuda. Esta opción le permite, por ejemplo, encontrar ayuda sobre una clase. Supongamos, por ejemplo, que desea conocer los métodos de los campos de entrada swing y JTextField. Escriba JTextField en el campo de búsqueda:

Image

La ayuda mostrará las entradas del índice que comienzan con el texto escrito:

Image

Ahora solo tienes que hacer doble clic en la entrada que te interese, en este caso JTextField class. La ayuda sobre esta clase se mostrará entonces en la ventana de la derecha:

Image

A continuación, se te proporcionará una descripción completa de la clase.

5.2.5. Algunos componentes de Swing

A continuación, presentamos diversas aplicaciones que utilizan los componentes swing más comunes, con el fin de descubrir sus principales métodos y propiedades. Para cada aplicación, mostramos la interfaz gráfica y el código relevante, en particular el de los manejadores de eventos.

5.2.5.1. Componentes JLabel y JTextField

Ya hemos visto estos dos componentes. JLabel es un componente de texto y JTextField, un componente de campo de entrada. Sus dos métodos principales son

String getText()
para obtener el contenido del campo de entrada o el texto de la etiqueta
void setText(String unTexte)
para insertar unTexte en el campo o en la etiqueta

Los eventos que se suelen utilizar para JTextField son los siguientes:

actionPerformed
indica que el usuario ha validado (tecla Enter) el texto ingresado
caretUpdate
indica que el usuario ha movido el cursor de entrada
inputMethodChanged
indica que el usuario ha modificado el campo de entrada

A continuación se muestra un ejemplo que utiliza el evento caretUpdate para dar seguimiento a los cambios en un campo de entrada:

Image

n.º
tipo
nombre
función
1
JTextField
txtSaisie
campo de entrada
2
JTextField
txtControle
muestra el texto de 1 en tiempo real
3
JButton
cmdEffacer
para borrar los campos 1 y 2
4
JButton
cmdQuitter
para salir de la aplicación

El código relevante de esta aplicación es el siguiente:

import java.awt.*;
....


public class Cadre1 extends JFrame {
  JPanel contentPane;
  JTextField txtSaisie = new JTextField();
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JTextField txtControle = new JTextField();
  JButton CmdEffacer = new JButton();
  JButton CmdQuitter = new JButton();

  /**Construir el marco*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    ....
    txtSaisie.addCaretListener(new javax.swing.event.CaretListener() {
      public void caretUpdate(CaretEvent e) {
        txtSaisie_caretUpdate(e);
      }
    });

...
    CmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdEffacer_actionPerformed(e);
      }
    });
...
    CmdQuitter.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        CmdQuitter_actionPerformed(e);
      }
    });
....
}

   /**Reemplazado, para que podamos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_caretUpdate(CaretEvent e) {
         // el cursor de entrada se movió
    txtControle.setText(txtSaisie.getText());
  }

  void CmdQuitter_actionPerformed(ActionEvent e) {
        // Salimos de la aplicación
    System.exit(0);
  }

  void CmdEffacer_actionPerformed(ActionEvent e) {
        // se borra el contenido del campo de entrada
    txtSaisie.setText("");
  }
}

A continuación se muestra un ejemplo de ejecución:

Image

5.2.5.2. componente JComboBox

Image

Image

Un componente JComboBox es una lista desplegable acompañada de un campo de entrada: el usuario puede elegir un elemento en (2) o escribir texto en (1). Por defecto, los JComboBox no son editables. Es necesario llamar explícitamente al método setEditable(true) para que sean editables. Para conocer la clase JComboBox, escribe JComboBox en el índice de la ayuda.

El objeto JComboBox se puede crear de diferentes maneras:

new JComboBox()
crea un combo vacío
new JComboBox (Object[] items)
crea un combo que contiene una matriz de objetos
new JComboBox(Vector items)
lo mismo con un vector de objetos

Puede sorprender que un combo pueda contener objetos cuando, por lo general, contiene cadenas de caracteres. Visualmente, así será. Si un JComboBox contiene un objeto obj, muestra la cadena obj.toString(). Recordemos que todo objeto cuenta con un método toString heredado de la clase Object, el cual devuelve una cadena de caracteres «representativa» del objeto.

Los métodos útiles de la clase JCombobox son los siguientes:

void addItem(Object unObjet)
agrega un objeto al menú desplegable
int getItemCount()
devuelve el número de elementos del menú desplegable
Object getItemAt(int i)
devuelve el objeto n.º i del menú desplegable
void insertItemAt(Object unObjet, int i)
inserta unObjet en la posición i del combo
int getSelectedIndex()
devuelve el número del elemento seleccionado en el menú desplegable
Object getSelectedItem()
devuelve el objeto seleccionado en el menú desplegable
void setSelectedIndex(int i)
selecciona el elemento i del menú desplegable
void setSelectedItem(Object unObjet)
selecciona el objeto especificado en el menú desplegable
void removeAllItems()
vacía el menú desplegable
void removeItemAt(int i)
elimina el elemento n.º i del menú desplegable
void removeItem(Object unObjet)
elimina el objeto especificado del menú desplegable
void setEditable(boolean val)
hace que el combo sea editable (val=true) o no (val=false)

Al seleccionar un elemento de la lista desplegable, se produce el evento actionPerformed, el cual puede utilizarse para recibir una notificación sobre el cambio de selección en el cuadro combinado. En la siguiente aplicación, utilizamos este evento para mostrar el elemento que se ha seleccionado en la lista.

Image

Solo presentamos el código relevante de la ventana.

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JComboBox jComboBox1 = new JComboBox();
  JLabel jLabel1 = new JLabel();

   /**Crear el cuadro*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // procesamiento: se llena el menú desplegable
    String[] infos={"un","deux","trois","quatre"};
    for(int i=0;i<infos.length;i++)
      jComboBox1.addItem(infos[i]);
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
        ....

    jComboBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jComboBox1_actionPerformed(e);
      }
    });
       .... 
  }

  void jComboBox1_actionPerformed(ActionEvent e) {
        // Se ha seleccionado un nuevo elemento: se muestra
    JOptionPane.showMessageDialog(this,jComboBox1.getSelectedItem(),
"actionPerformed",JOptionPane.INFORMATION_MESSAGE);
  }

}

5.2.5.3. Componente JList

El componente Swing JList es más complejo que su equivalente de la biblioteca awt. Existen dos diferencias importantes:

  • el contenido de la lista es administrado por un objeto distinto de la lista misma. Aquí utilizaremos un objeto DefaultListModel, que se usa como un Vector, pero que además notifica al objeto JList tan pronto como cambia su contenido, para que la visualización de la lista también cambie.
  • La lista no tiene desplazamiento por defecto. Es necesario colocar la lista dentro de un contenedor ScrollPane, el cual permite dicho desplazamiento.

En el código fuente, la definición de una lista se puede realizar de la siguiente manera:

      // el vector de valores de la lista 
DefaultlistModel valeurs=new DefaultListModel();
// la lista misma a la que se asocia el vector de sus valores
  JList jList1 = new JList(valeurs);
     // el contenedor desplazable en el que se coloca la lista para tener una lista desplazable
  JScrollPane jScrollPane1 = new JScrollPane(jList1);

Para incluir la lista jList1 en el contenedor jScrollPane1, el código generado por JBuilder procede de manera diferente:

  • declaración del contenedor en los atributos de la ventana
  JScrollPane jScrollPane1 = new JScrollPane();
  • luego, en el código de jbInit, la lista se asocia al contenedor
    jScrollPane1.getViewport().add(jList1, null);

Para agregar valores a la lista JList1 anterior, basta con agregarlos a su vector de valores valeurs:

    // inicializar lista
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);

y así se obtiene la siguiente ventana:

Image

¿Cómo se construye esta interfaz?

  • Seleccionamos un componente JScrollPane en la página «Contenedores Swing» de los componentes y lo colocamos en la ventana, ajustando su tamaño al deseado
  • Se selecciona un componente JList en la página «Swing» de los componentes y se coloca en el contenedor JScrollPane, donde ocupa todo el espacio.

El código generado por JBuilder debe modificarse ligeramente para obtener el siguiente código:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel2 = new JLabel();


   /**Construir el marco*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // procesamiento
     // se incluye la lista en el scrollPane
    // inicializar lista
    for(int i=0;i<10;i++)
      valeurs.addElement(""+i);
  }

   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
        ....
         // la lista jList1 está asociada al contenedor jcrollPane1
    jScrollPane1.getViewport().add(jList1, null);
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
        ....
  }
}

Ahora veamos los métodos principales de la clase JList buscando JList en el índice de la ayuda. El objeto JList se puede crear de diferentes maneras:

Image

Un método sencillo es el que hemos utilizado: crear un DefaultListModel con V vacío y luego asociarlo a la lista que se va a crear mediante new JList(V). El contenido de la lista no lo administra el objeto JList, sino el objeto que contiene los valores de la lista. Si el contenido se ha creado con un objeto DefaultListModel basado en la clase Vector, se podrán utilizar los métodos de la clase Vector para agregar, insertar y eliminar elementos de la lista. Una lista puede ser de selección simple o múltiple. Esto se establece mediante el método setSelectionMode:

Image

Se puede conocer el modo de selección actual con getSelectionMode:

Image

El elemento o los elementos seleccionados se pueden obtener mediante los siguientes métodos:

Image

Sabemos cómo asociar un vector de valores a una lista con el constructor JList(DefaultListModel). A la inversa, podemos obtener el objeto DefaultListModel de una lista JList mediante:

Image

Ya sabemos lo suficiente para escribir la siguiente aplicación:

Image

Los componentes de esta ventana son los siguientes:

n.º
tipo
nombre
función
1
JTextField
txtSaisie
campo de entrada
2
JList
jList1
lista contenida en un contenedor jScrollPane1
3
JList
jList2
lista contenida en un contenedor jScrollPane2
4
JButton
cmd1To2
transfiere los elementos seleccionados de la lista 1 a la lista 2
5
JButton
cmd2To1
hace lo contrario
6
JButton
cmdRaz1
vacía la lista 1
7
JButton
cmdRaz2
borra la lista 2

El usuario escribe texto en el campo (1) y lo valida. Entonces se produce el evento actionPerformed en el campo de entrada, que se utiliza para agregar el texto ingresado a la lista 1. Este es el código necesario para esta primera función:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Construir el marco*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 se coloca en el contenedor jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 se coloca en el contenedor jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // el texto ingresado ha sido validado
     // se recupera sin los espacios iniciales y finales
    String texte=txtSaisie.getText().trim();
     // si está vacío, no lo queremos
    if(texte.equals("")){
      // mensaje de error
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // fin
      return;
    }//si
    // si no está vacío, lo agregamos a los valores de la lista 1
    v1.addElement(texte);
     // y se borra el campo de entrada
    txtSaisie.setText("");
  }/// txtSaisie_actionperformed
}//clase

El código para transferir los elementos seleccionados de una lista a la otra es el siguiente:

  void cmd1To2_actionPerformed(ActionEvent e) {
    // transferencia de los elementos seleccionados de la lista 1 a la lista 2
    transfert(jList1,jList2);
  }//cmd1To2

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transferencia de los elementos seleccionados en jList2 a jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  private void transfert(JList L1, JList L2){
      // transferencia de los elementos seleccionados de la lista 1 a la lista 2
       // se recupera la tabla de índices de los elementos seleccionados en L1
      int[] indices=L1.getSelectedIndices();
      // ¿Hay algo que hacer?
      if (indices.length==0) return;
      // se recuperan los valores de L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // y los de L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // se agregan a L2 los valores seleccionados en L1
        v2.addElement(v1.elementAt(indices[i]));
        // los elementos de L1 copiados en L2 deben eliminarse de L1
        v1.removeElementAt(indices[i]);
      }//para
  }//transferencia

El código asociado a los botones Raz es muy sencillo:

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // vaciar lista 1
    v1.removeAllElements();
  }//comando Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // borrar lista 2
    v2.removeAllElements();
  }///comando Raz2

5.2.5.4. Casillas de selección JCheckBox, botones de opción JButtonRadio

Nos proponemos escribir la siguiente aplicación:

Image

Los componentes de la ventana son los siguientes:

n.º
tipo
nombre
función
1
JButtonRadio
jButtonRadio1
jButtonRadio2
jButtonRadio3
3 botones de opción que forman parte del grupo buttonGroup1
2
JCheckBox
jCheckBox1
jCheckBox2
jCheckBox3
3 casillas de selección
3
JList
jList1
una lista en un contenedor jScrollPane1
4
ButtonGroup
buttonGroup1
Componente no visible: sirve para agrupar los tres botones de opción, de modo que cuando uno de ellos se active, los demás se desactiven.

Un grupo de botones de opción se puede crear de la siguiente manera:

  • se colocan cada uno de los botones de opción sin preocuparse por agruparlos
  • se coloca en el contenedor un componente Swing ButtonGroup. Este componente no es visual. Por lo tanto, no aparece en el diseñador de la ventana. Sin embargo, sí aparece en su estructura:

Image

Arriba, en la rama Autre, se ven los atributos no visuales de la ventana. Una vez creado un grupo de botones de opción, se le pueden asignar cada uno de los botones de opción. Para ello, se seleccionan las propiedades del botón de opción:

Image

y en la propiedad buttonGroup del botón de opción, se ingresa el nombre del grupo al que se desea asignar el botón de opción, en este caso buttonGroup1. Se repite esta operación para los tres botones de opción.

El método principal de los botones de radio y las casillas de selección es el método isSelected(), que indica si la casilla o el botón está marcado. El texto asociado al componente se puede obtener con getText() y establecer con setText(String unTexte). La casilla o el botón de opción se puede marcar con el método setSelected(boolean value).

Al hacer clic en un botón de radio o en una casilla de selección, se activa el evento actionPerformed. En el código siguiente, utilizamos este evento para rastrear los cambios en los valores de los botones de radio y las casillas de selección:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JRadioButton jRadioButton1 = new JRadioButton();
  JRadioButton jRadioButton2 = new JRadioButton();
  JRadioButton jRadioButton3 = new JRadioButton();
  JCheckBox jCheckBox1 = new JCheckBox();
  JCheckBox jCheckBox2 = new JCheckBox();
  JCheckBox jCheckBox3 = new JCheckBox();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList jList1 = new JList(valeurs);

   /**Construir el marco*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    jRadioButton1.setSelected(true);
    jRadioButton1.setText("un");
    jRadioButton1.setBounds(new Rectangle(57, 31, 49, 23));
    jRadioButton1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });

    jRadioButton2.setBounds(new Rectangle(113, 30, 49, 23));
    jRadioButton2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton2.setText("deux");

    jRadioButton3.setBounds(new Rectangle(168, 30, 49, 23));
    jRadioButton3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheRadioButtons(e);
      }
    });
    jRadioButton3.setText("trois");

// los botones de opción están agrupados
    buttonGroup1.add(jRadioButton1);
    buttonGroup1.add(jRadioButton2);
    buttonGroup1.add(jRadioButton3);

// casillas de selección
    jCheckBox1.setText("A");
    jCheckBox1.setBounds(new Rectangle(58, 69, 32, 17));
    jCheckBox1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    jCheckBox2.setBounds(new Rectangle(112, 69, 40, 17));
    jCheckBox2.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });
    jCheckBox2.setText("B");

    jCheckBox3.setText("C");
    jCheckBox3.setBounds(new Rectangle(170, 69, 37, 17));
    jCheckBox3.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        afficheCases(e);
      }
    });

    ....
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
        ...
  }

  private void afficheRadioButtons(ActionEvent e){
     // muestra los valores de los 3 botones de opción
    valeurs.addElement("boutons radio=("+jRadioButton1.isSelected()+","+
      jRadioButton2.isSelected()+","+jRadioButton3.isSelected()+")");
  }//afficheRadioButtons

  void afficheCases(ActionEvent e) {
     // muestra los valores de las casillas de selección
    valeurs.addElement("cases à cocher=["+jCheckBox1.isSelected()+","+
      jCheckBox2.isSelected()+","+jCheckBox3.isSelected()+")");
  }//afficheCases

}//clasifica

A continuación se muestra un ejemplo de ejecución:

Image

5.2.5.5. componente JScrollBar

Creemos la siguiente aplicación:

Image

n.º
tipo
nombre
función
1
JScrollBar
jScrollBar1
un variador horizontal
2
JScrollBar
jScrollBar2
un variador vertical
3
JTextField
txtvaleurHS
muestra el valor del variador horizontal 1; también permite fijar este valor
4
JTextField
txtvaleurVS
muestra el valor del regulador vertical 2; también permite fijar este valor
  • Un control deslizante JScrollBar permite al usuario seleccionar un valor dentro de un rango de valores enteros, representado por la «banda» del control deslizante sobre la que se desplaza un cursor.
  • En un control deslizante horizontal, el extremo izquierdo representa el valor mínimo del rango, el extremo derecho el valor máximo y el cursor el valor actual seleccionado. En un control deslizante vertical, el mínimo está representado por el extremo superior y el máximo por el extremo inferior. El par (mín., máx.) tiene un valor predeterminado de (0,100).
  • Al hacer clic en los extremos del regulador, el valor varía en un incremento (positivo o negativo) según el extremo en el que se haga clic, denominado unitIncrement, cuyo valor predeterminado es 1.
  • Al hacer clic a ambos lados del cursor, el valor varía en un incremento (positivo o negativo) según el extremo en el que se haga clic, denominado blockIncrement, cuyo valor predeterminado es 10.
  • Estos cinco valores (mín., máx., valor, unitIncrement, blockIncrement) se pueden obtener mediante los métodos getMinimum(), getMaximum(), getValue(), getUnitIncrement(), getBlockIncrement(), los cuales devuelven un entero y pueden establecerse mediante los métodos setMinimum(int min), setMaximum(int max), setValue(int val), setUnitIncrement(int uInc), setBlockIncrement(int bInc)

Hay algunos puntos que debes conocer al utilizar los componentes JScrollBar. En primer lugar, se encuentra en la barra de componentes de Swing:

Image

Al colocarlo en el contenedor, por defecto se muestra en posición vertical. Se puede cambiar a horizontal con la propiedad orientation que se muestra a continuación:

Image

En la hoja de propiedades anterior se observa que tenemos acceso a las propiedades minimum, maximum, value, unitIncrement, blockIncrement del JScrollbar. Por lo tanto, se pueden configurar en el diseño. Cuando se coloca una barra de desplazamiento en el contenedor, su «banda de variación» no aparece:

Image

Este problema se puede solucionar asignando un borde al componente. Esto se hace mediante su propiedad border, que puede tomar diferentes valores:

Image

Este es el resultado, por ejemplo, de RaisedBevel:

Image

Al hacer clic en el extremo superior de un control deslizante vertical, su valor disminuye. Esto puede sorprender al usuario promedio, quien normalmente espera que el valor «aumente». Este problema se resuelve asignando un valor negativo a unitIncrement y blockIncrement.

¿Cómo se puede seguir la evolución de un control deslizante? Cuando cambia su valor, se produce el evento adjustmentValueChanged. Basta con asociar un procedimiento a este evento para recibir una notificación cada vez que varíe el valor de la barra de desplazamiento.

Image

El código útil de nuestra aplicación es el siguiente:

....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JScrollBar jScrollBar1 = new JScrollBar();
  Border border1;
  JTextField txtValeurHS = new JTextField();
  JScrollBar jScrollBar2 = new JScrollBar();
  JTextField txtValeurVS = new JTextField();
  TitledBorder titledBorder1;

   /**Construir el marco*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
...

// un borde para las barras de desplazamiento
    border1 = BorderFactory.createBevelBorder(BevelBorder.RAISED,Color.white,Color.white,new Color(134, 134, 134),new Color(93, 93, 93));
        // sin título en el borde
    titledBorder1 = new TitledBorder("");

    jScrollBar1.setOrientation(JScrollBar.HORIZONTAL);
    jScrollBar1.setBorder(BorderFactory.createRaisedBevelBorder());
    jScrollBar1.setAutoscrolls(true);
    jScrollBar1.setBounds(new Rectangle(37, 17, 218, 20));
    jScrollBar1.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar1_adjustmentValueChanged(e);
      }
    });

    txtValeurHS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurHS_actionPerformed(e);
      }
    });

    jScrollBar2.setBounds(new Rectangle(39, 51, 30, 27));
    jScrollBar2.addAdjustmentListener(new java.awt.event.AdjustmentListener() {
      public void adjustmentValueChanged(AdjustmentEvent e) {
        jScrollBar2_adjustmentValueChanged(e);
      }
    });
    jScrollBar2.setAutoscrolls(true);
    jScrollBar2.setUnitIncrement(-1);
    jScrollBar2.setBorder(BorderFactory.createRaisedBevelBorder());

    txtValeurVS.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtValeurVS_actionPerformed(e);
      }
    });

    ......
  }

   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void jScrollBar1_adjustmentValueChanged(AdjustmentEvent e) {
    // el valor de la barra de desplazamiento 1 ha cambiado
    txtValeurHS.setText(""+jScrollBar1.getValue());
  }

  void jScrollBar2_adjustmentValueChanged(AdjustmentEvent e) {
    // el valor de la barra de desplazamiento 2 ha cambiado
    txtValeurVS.setText(""+jScrollBar2.getValue());
  }

  void txtValeurHS_actionPerformed(ActionEvent e) {
    // se fija el valor de la barra de desplazamiento horizontal
    setValeur(jScrollBar1,txtValeurHS);
  }

  void txtValeurVS_actionPerformed(ActionEvent e) {
    // se fija el valor de la barra de desplazamiento vertical
    setValeur(jScrollBar2,txtValeurVS);
  }

  private void setValeur(JScrollBar jS, JTextField jT){
     // fija el valor de la barra de desplazamiento jS con el texto del campo jT
    int valeur=0;
    try{
      valeur=Integer.parseInt(jT.getText());
      jS.setValue(valeur);
    }
    catch (Exception e){
      // se muestra el error
      afficher(""+e);
    }//try-catch
  }//setValeur

  void afficher(String message){
    // muestra un mensaje en un cuadro
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//mostrar

}

A continuación se muestra un ejemplo de ejecución:

Image

5.2.5.6. Componente JTextArea

El componente JTextArea es un componente en el que se pueden ingresar varias líneas de texto, a diferencia del componente JTextField, en el que solo se puede ingresar una línea. Si este componente se coloca en un contenedor con desplazamiento (JScrollPane), se obtiene un campo de entrada de texto con desplazamiento. Este tipo de componente podría encontrarse, por ejemplo, en una aplicación de correo electrónico, donde el texto del mensaje que se va a enviar se escribiría en un componente JTextArea. Los métodos habituales son String getText() para conocer el contenido del campo de texto, setText(String unTexte) para insertar unTexte en el campo de texto, y append(String unTexte) para agregar unTexte al texto que ya se encuentra en el campo de texto. Consideremos la siguiente aplicación:

Image

n.º
tipo
nombre
función
1
JTextArea
txtTexte
un campo de texto de varias líneas
2
JButton
cmdAfficher
muestra el contenido de 1 en un cuadro de diálogo
3
JButton
cmdEffacer
borra el contenido de 1
4
JTextField
txtAjout
texto agregado al texto de 1 al presionar la tecla Enter.
5
JScrollPane
jScrollPane1
Contenedor con desplazamiento en el que se ha colocado el cuadro de texto 1 para crear un cuadro de texto con desplazamiento.

El código correspondiente es el siguiente:

.....

public class cadreAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JButton cmdAfficher = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JLabel jLabel2 = new JLabel();
  JTextField txtAjout = new JTextField();
  JButton cmdEffacer = new JButton();

  /**Crear el marco*/
  public cadreAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {

    cmdAfficher.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdAfficher_actionPerformed(e);
      }
    });
    txtAjout.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtAjout_actionPerformed(e);
      }
    });
    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });
    .......
    jScrollPane1.getViewport().add(txtTexte, null);
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
        ........
  }

  void cmdAfficher_actionPerformed(ActionEvent e) {
    // muestra el contenido de TextArea
    afficher(txtTexte.getText());
  }

    void afficher(String message){
     // muestra un mensaje en un cuadro
    JOptionPane.showMessageDialog(this,message,"Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// mostrar

  void cmdEffacer_actionPerformed(ActionEvent e) {
    txtTexte.setText("");
  }//cmdEffacer_actionPerformed

  void txtAjout_actionPerformed(ActionEvent e) {
    // agregar texto
    txtTexte.append(txtAjout.getText());
     // borrar y volver a agregar
    txtAjout.setText("");
  }//
}

5.2.6. Eventos del ratón

Al dibujar en un contenedor, es importante conocer la posición del ratón para, por ejemplo, mostrar un punto al hacer clic. Los movimientos del ratón provocan eventos en el contenedor por el que se desplaza. A continuación se muestran, por ejemplo, los que ofrece JBuilder para un contenedor JPanel:

Image

mouseClicked
clic del ratón
mouseDragged
el ratón se desplaza, botón izquierdo presionado
mouseEntered
el ratón acaba de entrar en el área del contenedor
mouseExited
el ratón acaba de salir de la superficie del contenedor
mouseMoved
el ratón se mueve
mousePressed
Se presiona el botón izquierdo del ratón
mouseReleased
Se suelta el botón izquierdo del ratón

Aquí hay un programa que te ayudará a entender mejor en qué momentos ocurren los diferentes eventos del ratón:

Image

n.º
tipo
nombre
función
1
JTextField
txtPosition
para mostrar la posición del ratón en el contenedor (si corresponde, MouseMoved)
2
JList
lstAffichage
para mostrar los eventos del ratón distintos de MouseMoved
3
JButton
cmdEffacer
para borrar el contenido de 2

Al ejecutar este programa, esto es lo que se obtiene al hacer clic:

Image

Los eventos se apilan de arriba hacia abajo en la lista. Por lo tanto, la captura de pantalla anterior indica que un clic genera tres eventos, en el siguiente orden:

  1. MousePressed al presionar el botón
  2. MouseReleased al soltarlo
  3. MouseClicked, lo cual indica que la sucesión de los dos eventos anteriores se considera un clic. Podría tratarse de un doble clic. Sin embargo, en el ejemplo anterior, la información clickCount=1 indica que se trata de un clic simple.

Ahora, si presionas el botón, mueves el ratón y sueltas el botón:

Image

Aquí vemos los tres eventos:

  1. MousePressed al presionar inicialmente el botón
  2. MouseDragged al mover el ratón con el botón presionado
  3. MouseReleased al soltar el botón

En los dos ejemplos anteriores, se observa que un evento del ratón trae consigo diversa información, entre ella las coordenadas (x, y) del ratón, por ejemplo (408,65) en la primera línea anterior.

Si seguimos así, descubrimos que el evento MouseExited se activa tan pronto como el ratón sale del contenedor o pasa sobre uno de sus componentes. En este último caso, el contenedor recibe el evento MouseExited y el componente, el evento MouseEntered. Lo contrario ocurrirá cuando el ratón salga del componente para volver al contenedor.

¿Qué sucede al hacer doble clic?

Image

Se producen exactamente los mismos eventos que con un clic simple. Solo que el evento incluye la información clickCount=2 (véase más arriba), lo que indica que, de hecho, se ha producido un doble clic.

El código útil de esta aplicación es el siguiente:

public class Cadre1 extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtPosition = new JTextField();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel valeurs=new DefaultListModel();
  JList lstAffichage = new JList(valeurs);
  JButton cmdEffacer = new JButton();

  /**Construir el marco*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {

    contentPane.addMouseMotionListener(new java.awt.event.MouseMotionAdapter() {
      public void mouseMoved(MouseEvent e) {
        contentPane_mouseMoved(e);
      }
      public void mouseDragged(MouseEvent e) {
        contentPane_mouseDragged(e);
      }
    });

    contentPane.addMouseListener(new java.awt.event.MouseAdapter() {
      public void mouseEntered(MouseEvent e) {
        contentPane_mouseEntered(e);
      }
      public void mouseExited(MouseEvent e) {
        contentPane_mouseExited(e);
      }
      public void mousePressed(MouseEvent e) {
        contentPane_mousePressed(e);
      }
      public void mouseClicked(MouseEvent e) {
        contentPane_mouseClicked(e);
      }
      public void mouseReleased(MouseEvent e) {
        contentPane_mouseReleased(e);
      }
    });

    cmdEffacer.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        cmdEffacer_actionPerformed(e);
      }
    });

    jScrollPane1.getViewport().add(lstAffichage, null);

...............
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
    .........
  }

  void contentPane_mouseMoved(MouseEvent e) {
    txtPosition.setText("("+e.getX()+","+e.getY()+")");
  }

  void contentPane_mouseDragged(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseEntered(MouseEvent e) {
    afficher(e);
  }

  void afficher(MouseEvent e){
     // muestra el evento e en la lista lstAffichage
    valeurs.insertElementAt(e,0);
  }

  void contentPane_mouseExited(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mousePressed(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseClicked(MouseEvent e) {
    afficher(e);
  }

  void contentPane_mouseReleased(MouseEvent e) {
    afficher(e);
  }

  void cmdEffacer_actionPerformed(ActionEvent e) {
     // borra la lista
    valeurs.removeAllElements();
  }
}

5.2.7. Crear una ventana con menú

Ahora veamos cómo crear una ventana con menú usando JBuilder. Vamos a crear la siguiente ventana:

Image

Image

Crea un nuevo proyecto que comience con una ventana vacía. Selecciona en la lista de componentes «Contenedores Swing» el componente JMenuBar (véase la figura 1 a continuación) y arrástralo a la ventana que estás diseñando.

Image

No aparece nada en la ventana de diseño, pero el componente JMenuBar aparece en el panel de estructura de su ventana:

Image

Haga doble clic en el elemento jMenuBar1 anterior para acceder al menú en modo de diseño:

Image

1
Insertar un elemento de menú
2
Insertar un separador
3
Insertar un menú anidado
4
Eliminar un elemento del menú
5
Desactivar un elemento del menú
6
elemento de menú con casilla de selección
7
Invertir el botón de opción

Para crear tu primer elemento de menú, escribe «Opciones A» en el recuadro A de arriba y, a continuación, debajo, en este orden: A1, A2, separador, A3, A4.

Image

Luego, al lado:

Image

Utilice la herramienta 3 para indicar que B3 es un submenú anidado.

A medida que avanzamos en el diseño del menú, la estructura lógica de nuestra ventana va cambiando:

Image

Si ejecutamos nuestra aplicación ahora, veremos una ventana vacía sin menú. Necesitamos asociar el menú creado a nuestra ventana. Para ello, en la estructura de la ventana, selecciona el objeto this:

Image

De esta manera, tendrá acceso a las propiedades de this:

Image

Una de ellas es JMenuBar, que sirve para establecer el menú que se asociará a la ventana. Haga clic en la celda a la derecha de JMenuBar. Se le mostrarán todos los menús creados. En este caso, solo tendremos jMenuBar1. Selecciónelo.

Ejecute la aplicación (F9):

Image

Ahora tenemos un menú, pero las opciones, por el momento, no hacen nada. Las opciones del menú se tratan como componentes: tienen propiedades y eventos. En la estructura del menú, selecciona la opción jMenuItem1:

Image

De esta manera, tendrá acceso a sus propiedades y eventos:

Image

Seleccione la página de eventos y haga clic en la celda a la derecha del evento actionPerformed: este es el evento que ocurre al hacer clic en un elemento del menú. Se le propone un procedimiento de procesamiento por defecto. Haga doble clic en él para acceder a su código:

Image

Escribiremos el siguiente código sencillo:

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // muestra un mensaje en un cuadro de diálogo
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//mostrar

Ejecute la aplicación y seleccione la opción A1 para obtener el siguiente mensaje:

Image

El código útil de esta aplicación es el siguiente:

.....

public class Cadre1 extends JFrame {
  JPanel contentPane;
  BorderLayout borderLayout1 = new BorderLayout();
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem jMenuItem1 = new JMenuItem();
  JMenuItem jMenuItem2 = new JMenuItem();
  JMenuItem jMenuItem3 = new JMenuItem();
  JMenuItem jMenuItem4 = new JMenuItem();
  JMenu jMenu2 = new JMenu();
  JMenuItem jMenuItem5 = new JMenuItem();
  JMenuItem jMenuItem6 = new JMenuItem();
  JMenu jMenu3 = new JMenu();
  JMenuItem jMenuItem7 = new JMenuItem();
  JMenuItem jMenuItem8 = new JMenuItem();
  JMenuItem jMenuItem9 = new JMenuItem();

  /**Crear el marco*/
  public Cadre1() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }
   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
        // la ventana está vinculada a un menú
    this.setJMenuBar(jMenuBar1);

    jMenu1.setText("Options A");
    jMenuItem1.setText("A1");
    jMenuItem1.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        jMenuItem1_actionPerformed(e);
      }
    });
    jMenuItem2.setText("A2");
    jMenuItem3.setText("A3");
    jMenuItem4.setText("A4");
    jMenu2.setText("Options B");
    jMenuItem5.setText("B1");
    jMenuItem6.setText("B2");
    jMenu3.setText("B3");
    jMenuItem7.setText("B31");
    jMenuItem8.setText("B32");
    jMenuItem9.setText("B4");
    jMenuBar1.add(jMenu1);
    jMenuBar1.add(jMenu2);
    jMenu1.add(jMenuItem1);
    jMenu1.add(jMenuItem2);
    jMenu1.addSeparator();
    jMenu1.add(jMenuItem3);
    jMenu1.add(jMenuItem4);
    jMenu2.add(jMenuItem5);
    jMenu2.add(jMenuItem6);
    jMenu2.add(jMenu3);
    jMenu2.add(jMenuItem9);
    jMenu3.add(jMenuItem7);
    jMenu3.add(jMenuItem8);
  }
   /**Reemplazado, así podemos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
....
  }

  void jMenuItem1_actionPerformed(ActionEvent e) {
    afficher("L'option A1 a été sélectionnée");
  }

  void afficher(String message){
     // muestra un mensaje en un cuadro de diálogo
    JOptionPane.showMessageDialog(this,message,"Menus",JOptionPane.INFORMATION_MESSAGE);
  }//mostrar

}

5.3.1. Cuadros de mensaje

Ya hemos utilizado la clase JOptionPane para mostrar mensajes. Así, el siguiente código:

import javax.swing.*;

public class dialog1 {
  public static void main(String arg[]){
    JOptionPane.showMessageDialog(null,"Un message","Titre de la boîte",JOptionPane.INFORMATION_MESSAGE);
  }
}

genera la siguiente ventana:

Image

Al cerrar esta ventana, esta desaparece, pero el hilo de ejecución en el que se ejecutaba no se detiene. Este fenómeno no suele ocurrir. Los cuadros de diálogo se utilizan dentro de una aplicación que, en algún momento, utiliza una instrucción System.exit(n) para detener todos los hilos. Lo tendremos presente en los ejemplos siguientes, todos basados en el mismo modelo. En DOS, la aplicación se puede interrumpir con Ctrl-C. Con JBuilder, se utilizará la opción Ejecutar/Reiniciar el programa (Ctrl-F2). Por otra parte, el primer argumento de showMessageDialog es aquí null. Por lo general, este no es el caso. Suele ser this, donde this designa la ventana principal de la aplicación.

5.3.2. Apariencia y comportamiento

La apariencia del cuadro anterior podría ser diferente. Es posible configurar esta apariencia mediante la clase javax.swing.UIManager. Cuando comentamos el código generado por JBuilder para nuestra primera ventana, nos encontramos con una instrucción en la que no nos detuvimos:

      UIManager.setLookAndFeel(UIManager.getSystemLookAndFeelClassName());

El método setLookAndFeel de la clase UIManager (UI = Interfaz de usuario) permite definir la apariencia de las interfaces gráficas. La clase UIManager cuenta con un método que permite conocer las «apariencias» posibles para las interfaces:

static UIManager.LookAndFeelInfo[]
getInstalledLookAndFeels()

El método devuelve una matriz de elementos de tipo LookAndFeelInfo. Esta clase tiene un método:

String
getClassName()

que devuelve el nombre de la clase que «implementa» una apariencia determinada. Probemos el siguiente programa:

import javax.swing.*;

public class LookAndFeels {
  // muestra los «look and feels» disponibles
  public static void main(String[] args) {
    // enumera los «look and feels» instalados
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // visualización
    for(int i=0;i<lf.length;i++){
      System.out.println(lf[i].getClassName());
    }//para
  }//principal
}//clasifica

Arroja los siguientes resultados:

javax.swing.plaf.metal.MetalLookAndFeel
com.sun.java.swing.plaf.motif.MotifLookAndFeel
com.sun.java.swing.plaf.windows.WindowsLookAndFeel

Por lo tanto, parece haber tres «estilos» diferentes. Volvamos a nuestro programa de visualización de mensajes probando los distintos estilos posibles:

import javax.swing.*;

public class LookAndFeel2 {
  // muestra los «look and feels» disponibles
  public static void main(String[] args) {
    // lista de los «look and feels» instalados
    UIManager.LookAndFeelInfo[] lf=UIManager.getInstalledLookAndFeels();
    // visualización
    for(int i=0;i<lf.length;i++){
      // administrador de apariencia
      try{
        UIManager.setLookAndFeel(lf[i].getClassName());
      }catch(Exception ex){
        System.err.println(ex.getMessage());
      }//captura
      // mensaje
      JOptionPane.showMessageDialog(null,"Un message",lf[i].getClassName(),JOptionPane.INFORMATION_MESSAGE);
    }//para
  }//main
}//clase

Al ejecutarlo, se obtienen las siguientes visualizaciones:

que corresponden, de derecha a izquierda, a los «estilos» Metal, Motivo y Windows.

5.3.3. Cuadros de confirmación

La clase JOptionPane cuenta con un método showConfirmDialog para mostrar cuadros de confirmación con los botones Oui, Non y Annuler. Existen varios métodos showConfirmDialog sobreescritos. Analizamos uno de ellos:

static int
showConfirmDialog(Component parentComponent, Object message, String title, int optionType)
parentComponent
el componente padre del cuadro de diálogo. A menudo es la ventana o el valor nulo
message
el mensaje que se mostrará
title
el título del cuadro de diálogo
optionType
JOptionPane.YES_NO_OPTION: botones Sí, No
JOptionPane.YES_NO_CANCEL_OPTION: botones «Sí», «No», «Cancelar»

El resultado devuelto por el método es:

JOptionPane.YES_OPTION
el usuario hizo clic en «Sí»
JOptionPane.NO_OPTION
El usuario hizo clic en «No»
JOptionPane.CANCEL_OPTION
el usuario hizo clic en «Cancelar»
JOptionPane.CLOSED_OPTION
El usuario cerró el cuadro de diálogo

Aquí hay un ejemplo:

import javax.swing.*;

public class confirm1 {
  public static void main(String[] args) {
    // muestra cuadros de confirmación
    int réponse;
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_OPTION));
    affiche(JOptionPane.showConfirmDialog(null,"Voulez-vous continuer ?","Confirmation",JOptionPane.YES_NO_CANCEL_OPTION));
  }//principal

  private static void affiche(int réponse){
     // indica qué tipo de respuesta se recibió
    switch(réponse){
      case JOptionPane.YES_OPTION :
        System.out.println("Oui");
        break;
      case JOptionPane.NO_OPTION :
        System.out.println("Non");
        break;
      case JOptionPane.CANCEL_OPTION :
        System.out.println("Annuler");
        break;
      case JOptionPane.CLOSED_OPTION :
        System.out.println("Fermeture");
        break;
    }//interruptor
  }//pantalla
}//clasificar

En la consola, se muestran los mensajes Non y Annuler.

5.3.4. Campo de entrada

La clase JOptionPane también ofrece la posibilidad de realizar una entrada con el método showInputDialog. Una vez más, existen varios métodos sobrecargados. Presentamos uno de ellos:

static String
showInputDialog(Component parentComponent, Object message, String title, int messageType)

Los argumentos son los mismos que ya hemos visto varias veces. El método devuelve la cadena de caracteres ingresada por el usuario. A continuación, un ejemplo:

import javax.swing.*;

public class input1 {
  public static void main(String[] args) {
    // ingreso
    System.out.println("Chaîne saisie ["+
      JOptionPane.showInputDialog(null,"Quel est votre nom","Saisie du nom",JOptionPane.QUESTION_MESSAGE )
      + "]");
  }//mano
}//clase

La visualización del cuadro de entrada:

Image

Visualización de la consola:

Chaîne saisie [dupont]

5.4. Cuadros de selección

Ahora nos enfocaremos en varios cuadros de selección predefinidos en Java 2:

JFileChooser
cuadro de selección que permite seleccionar un archivo en el árbol de archivos
JColorChooser
cuadro de selección que permite elegir un color

5.4.1. Cuadro de selección JFileChooser

Vamos a desarrollar la siguiente aplicación:

Image

Los controles son los siguientes:

N.º
tipo
nombre
función
0
JScrollPane
jScrollPane1
Container deslizante para el cuadro de texto 1
1
JTextArea, que a su vez se encuentra dentro de JScrollPane
txtTexte
texto escrito por el usuario o cargado desde un archivo
2
JButton
btnSauvegarder
permite guardar el texto de 1 en un archivo de texto
3
JButton
btnCharger
permite cargar el contenido de un archivo de texto en 1
4
JButton
btnEffacer
borra el contenido de 1

Se utiliza un control no visual: jFileChooser1. Este se toma de la paleta de contenedores Swing de JBuilder:

Image

Colocamos el componente en la ventana de diseño, pero fuera del formulario. Aparece en la lista de componentes:

Image

Ahora mostramos el código relevante del programa para tener una visión general:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;

public class dialogues extends JFrame {
   // los componentes del marco
  JPanel contentPane;
  JButton btnSauvegarder = new JButton();
  JButton btnCharger = new JButton();
  JButton btnEffacer = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  JTextArea txtTexte = new JTextArea();
  JFileChooser jFileChooser1 = new JFileChooser();

  // los filtros de archivos
  javax.swing.filechooser.FileFilter filtreTxt = null;

   //Construir el marco
  public dialogues() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
       // otras inicializaciones
      moreInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }

   // moreInit
  private void moreInit(){
     // inicializaciones al construir la ventana
     // filtro *.txt
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // ¿Se acepta «f»?
        return f.getName().toLowerCase().endsWith(".txt");
      }//aceptar
      public String getDescription(){
        // descripción del filtro
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // se agrega el filtro
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // también queremos el filtro de todos los archivos
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // se establece el directorio de origen de la caja FileChooser en el directorio actual
    jFileChooser1.setCurrentDirectory(new File("."));
  }

   //Inicializar el componente
  private void jbInit() throws Exception  {
.......................
  }
   //Reemplazado, así podemos salir cuando se cierre la ventana
  protected void processWindowEvent(WindowEvent e) {
......................
    }
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // selección de un archivo mediante un objeto JFileChooser

     // se establece el filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // se muestra el cuadro de selección
    int returnVal = jFileChooser1.showOpenDialog(this);
    // ¿El usuario ha seleccionado algo?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // se coloca el archivo en el campo de texto
       lireFichier(jFileChooser1.getSelectedFile());
    }//si
  }//btnCharger_actionPerformed

  // lireFichier
  private void lireFichier(File fichier){
     // muestra el contenido del archivo de texto «fichier» en el campo de texto

     // se borra el campo de texto
    txtTexte.setText("");

     // algunos datos
    BufferedReader IN=null;
    String ligne=null;
    try{
      // abre el archivo en modo de lectura
      IN=new BufferedReader(new FileReader(fichier));
      // se lee el archivo línea por línea
      while((ligne=IN.readLine())!=null){
        txtTexte.append(ligne+"\n");
      }//while
       // cierre del archivo
      IN.close();
    }catch(Exception ex){
       // se produjo un error
      txtTexte.setText(""+ex);
    }//catch
  }

  // borrar
  void btnEffacer_actionPerformed(ActionEvent e) {
    // se borra el cuadro de texto
    txtTexte.setText("");
  }

   // guardar
  void btnSauvegarder_actionPerformed(ActionEvent e) {
     // guarda el contenido del cuadro de texto en un archivo

     // se establece el filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // se muestra el cuadro de selección para guardar
    int returnVal = jFileChooser1.showSaveDialog(this);
    // ¿El usuario ha seleccionado algo?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // se escribe el contenido del cuadro de texto en un archivo
       écrireFichier(jFileChooser1.getSelectedFile());
    }//si
  }

   // lireFichier
  private void écrireFichier(File fichier){
     // escribe el contenido del cuadro de texto en un archivo

     // algunos datos
    PrintWriter PRN=null;
    try{
       // abre el archivo en modo de escritura
      PRN=new PrintWriter(new FileWriter(fichier));
      // se escribe el contenido del cuadro de texto
      PRN.print(txtTexte.getText());
       // cierra el archivo
      PRN.close();
    }catch(Exception ex){
       // se produjo un error
      txtTexte.setText(""+ex);
    }//captura
  }

No comentaremos el código de los métodos btnEffacer_Click, lireFichier y écrireFichier, ya que no aportan nada que no hayamos visto antes. Nos detendremos en la clase JFileChooser y su uso. Esta clase es compleja, del tipo «complicadísima». Aquí solo utilizamos los siguientes métodos:

addChoosableFilter(FileFilter)
establece los tipos de archivos que se ofrecen para la selección
setAcceptAllFileFilterUsed(boolean)
indica si el tipo «Todos los archivos» debe ofrecerse para la selección o no
File getSelectedFile()
el archivo (File) seleccionado por el usuario
int showSaveDialog()
método que muestra el cuadro de diálogo de selección de guardado. Devuelve un resultado de tipo int. El valor jFileChooser.APPROVE_OPTION indica que el usuario ha realizado una selección válida. De lo contrario, o bien ha cancelado la selección, o bien se ha producido un error.
setCurrentDirectory
para establecer el directorio inicial desde el cual el usuario comenzará a explorar el sistema de archivos
setFileFilter(FileFilter)
para establecer el filtro activo

El método showSaveDialog muestra un cuadro de selección similar al siguiente:

Image

1
lista desplegable creada con el método addChoosableFilter. Contiene lo que se conoce como filtros de selección, representados por la clase FileFilter. Es responsabilidad del desarrollador definir estos filtros y agregarlos a la lista 1.
2
carpeta actual, establecida por el método setCurrentDirectory si se ha utilizado dicho método; de lo contrario, la carpeta actual será la carpeta «Mis documentos» en Windows o el directorio de inicio en Unix.
3
nombre del archivo seleccionado o ingresado directamente por el usuario. Estará disponible con el método getSelectedFile()
4
Botones Guardar/Cancelar. Si se utiliza el botón Enregistrer, el método showSaveDialog devuelve el resultado jFileChooser.APPROVE_OPTION

¿Cómo se construyen los filtros de archivos de la lista desplegable 1? Los filtros se agregan a la lista 1 mediante el método:

addChoosableFilter(FileFilter)
establece los tipos de archivos que se ofrecen para la selección

de la clase JFileChooser. Nos queda por conocer la clase FileFilter. En realidad, se trata de la clase javax.swing.filechooser.FileFilter, que es una clase abstracta, c.a.d, una clase que no puede ser instanciada, sino solo derivada. Se define de la siguiente manera:

FileFilter()
constructor
boolean accept(File)
indica si el archivo f pertenece al filtro o no
String getDescription()
cadena de descripción del filtro

Veamos un ejemplo. Queremos que el menú desplegable 1 ofrezca un filtro para seleccionar los archivos *.txt con la descripción «Archivos de texto (*.txt)».

  • Debemos crear una clase derivada de la clase FileFilter
  • utilizar el método boolean accept(File f) para devolver el valor true si el nombre del archivo f termina en .txt
  • utilizar el método String getDescription() para generar la descripción «Archivos de texto (*.txt)»

Este filtro podría definirse en nuestra aplicación de la siguiente manera:

  javax.swing.filechooser.FileFilter filtreTxt = new javax.swing.filechooser.FileFilter(){
    public boolean accept(File f){
      // ¿Se acepta f?
      return f.getName().toLowerCase().endsWith(".txt");
    }//aceptado
    public String getDescription(){
      // descripción del filtro
      return "Fichiers Texte (*.txt)";
    }//getDescription
  };

Este filtro se agregaría a la lista de filtros del objeto jFileChooser1 mediante la instrucción:

     // se agrega el filtro *.txt
    jFileChooser1.addChoosableFileFilter(filtretxt);

Todo esto, junto con algunas otras inicializaciones, se realiza en el método moreInit, que se ejecuta al crear la ventana (véase el programa completo más arriba). El código del botón Sauvegarder es el siguiente:

  void btnSauvegarder_actionPerformed(ActionEvent e) {
    // guarda el contenido del cuadro de texto en un archivo

     // se establece el filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // se muestra el cuadro de selección para guardar
    int returnVal = jFileChooser1.showSaveDialog(this);
    // ¿El usuario ha seleccionado algo?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // se escribe el contenido del cuadro de texto en un archivo
       écrireFichier(jFileChooser1.getSelectedFile());
    }//si
  }

La secuencia de operaciones es la siguiente:

  • se establece el filtro activo en *.txt para permitir que el usuario busque preferentemente este tipo de archivos. El filtro «Todos los archivos» también está presente. Se agregó en el procedimiento moreInit. Por lo tanto, hay dos filtros.
  • Se muestra el cuadro de selección de guardado. Aquí perdemos el control, ya que el usuario utiliza el cuadro de selección para indicar un archivo del sistema de archivos.
  • Al salir del cuadro de selección, se comprueba el valor de retorno para ver si se debe guardar o no el cuadro de texto. En caso afirmativo, debe guardarse en el archivo obtenido mediante el método getSelectedFile.

El código relacionado con el botón «Cargar» es muy similar al del botón «Guardar».

  void btnCharger_actionPerformed(ActionEvent e) {
    // selección de un archivo mediante un objeto JFileChooser

     // se establece el filtro inicial
    jFileChooser1.setFileFilter(filtreTxt);
     // se muestra el cuadro de selección
    int returnVal = jFileChooser1.showOpenDialog(this);
    // ¿El usuario ha seleccionado algo?
    if(returnVal == JFileChooser.APPROVE_OPTION) {
      // se coloca el archivo en el campo de texto
       lireFichier(jFileChooser1.getSelectedFile());
    }//si
  }//btnCharger_actionPerformed

Hay dos diferencias:

  • para mostrar el cuadro de selección de archivos, se utiliza el método showOpenDialog en lugar del método showSaveDialog. El cuadro de selección que se muestra es similar al que muestra el método showSaveDialog.
  • Si el usuario ha seleccionado correctamente un archivo, se llama al método lireFichier en lugar del método écrireFichier.

5.4.1.1. Cuadros de selección JColorChooser y JFontChooser

Continuamos con el ejemplo anterior agregando dos botones nuevos:

Image

N.º
tipo
nombre
función
6
JButton
btnCouleur
para establecer el color de los caracteres de TextBox
7
JButton
btnPolice
para establecer la fuente de TextBox

El componente JColorChooser, que permite mostrar un cuadro de selección de color, se puede encontrar en la lista de componentes Swing de JBuilder:

Image

Colocamos este componente en la ventana de diseño, pero fuera del formulario. No es visible en el formulario, pero sí está presente en la lista de componentes de la ventana:

Image

La clase JColorChooser es muy sencilla. Mostramos el cuadro de selección de colores con el método int showDialog:

static Color
showDialog(Component component, String title, Color initialColor)
Component component
el componente padre del cuadro de selección, generalmente una ventana JFrame
String title
el título que aparece en la barra de título del cuadro de selección
Color intialColor
color seleccionado inicialmente en el cuadro de selección

Si el usuario elige un color, el método devuelve un color; de lo contrario, devuelve el valor null. El código asociado al botón Couleur es el siguiente:

  void btnCouleur_actionPerformed(ActionEvent e) {
     // selección de un color de texto con el componente JColorChooser
    Color couleur;
    if((couleur=jColorChooser1.showDialog(this,"Choix d'une couleur",Color.BLACK))!=null){
       // se establece el color de los caracteres del cuadro de texto
      txtTexte.setForeground(couleur);
    }//si
  }

La clase Color se define en java.awt.Color. En ella se definen varias constantes, entre ellas Color.BLACK para el color negro. El cuadro de selección que se muestra es el siguiente

Image

Curiosamente, la biblioteca Swing no ofrece una clase para seleccionar un tipo de letra. Afortunadamente, existen los recursos de Java en Internet. Al realizar una búsqueda con la palabra clave «JFontChooser», que parece un nombre posible para dicha clase, se encuentran varios resultados. El siguiente ejemplo nos dará la oportunidad de configurar JBuilder para que utilice paquetes no previstos en su configuración inicial.

El paquete recuperado se llama swingextras.jar y se ha colocado en la carpeta <jdk>\jre\lib\perso, donde <jdk> indica el directorio de instalación del JDK utilizado por JBuilder. Podría haberse ubicado en cualquier otro lugar.

Veamos el contenido del paquete SwingExtras.jar:

Image

Ahí se encuentra el código fuente Java de los componentes que ofrece el paquete. También se encuentran las clases mismas:

Image

De este archivo, cabe destacar que la clase JFontChooser se llama en realidad com.lamatek.swingextras.JFontChooser. Si no queremos escribir el nombre completo, tendremos que escribir al inicio del programa:

import com.lamatek.swingextras.*;

¿Cómo harán el compilador y la máquina virtual de Java para encontrar este nuevo paquete? En el caso del uso directo de JDK, esto ya se ha explicado y el lector puede consultar las explicaciones en el párrafo sobre los paquetes de Java. Aquí detallamos el método que se debe utilizar con JBuilder. Los paquetes se configuran en el menú Opciones/Configurar los JDK:

Image

1
El botón Modifier (1) permite indicarle a JBuilder qué JDK se debe utilizar. En este ejemplo, JBuilder había traído consigo el JDK 1.3.1. Cuando se lanzó el JDK 1.4, se instaló por separado del JBuilder y se utilizó el botón Modifier para indicarle al JBuilder queutilizar a partir de entonces el JDK 1.4, indicando el directorio de instalación de este último
2
directorio raíz de JDK, que actualmente utiliza JBuilder
3
lista de los archivos Java (.jar) utilizados por JBuilder. Se pueden agregar otros con el botón Ajouter (4)
4
El botón Ajouter (4) permite agregar nuevos paquetes que JBuilder utilizará tanto para la compilación como para la ejecución de los programas. Aquí lo hemos utilizado para agregar el paquete SwingExtras.jar (5)

Ahora JBuilder está correctamente configurado para poder utilizar la clase JFontChooser. Sin embargo, necesitaríamos tener acceso a la definición de esta clase para usarla correctamente. El archivo swingextras.jar contiene archivos HTML que podríamos extraer para aprovecharlos. No es necesario. Se puede acceder directamente a la documentación de Java incluida en los archivos .jar desde JBuilder. Para ello, hay que configurar la pestaña Documentation (6) que se muestra arriba. Aparecerá la siguiente ventana:

Image

El botón Ajouter nos permite indicar que el archivo SwingExtras.jar debe ser explorado en busca de documentación. Una vez validado este paso, podemos constatar que efectivamente tenemos acceso a la documentación de SwingExtras.jar. Esto se traduce en diversas facilidades:

  • si comenzamos a escribir la instrucción de importación
import com.lamatek.swingextras.*;

, veremos que JBuilder nos ofrece ayuda:

Image

El paquete com.lamatek se ha encontrado correctamente.

  • Ahora, si pasamos al siguiente programa:
import com.lamatek.swingextras.*;

public class test{
  JFontChooser jFontChooser1=null;
}  

Al buscar «F1» con la palabra clave «JFontChooser», se obtiene ayuda sobre esta clase:

Image

En la barra de estado 1 se ve que, efectivamente, se está utilizando un archivo HTML del paquete swingextras.jar. El ejemplo presentado anteriormente es lo suficientemente claro como para que podamos escribir el código del botón Police de nuestra aplicación:

  void btnPolice_actionPerformed(ActionEvent e) {
    // selección de una fuente de texto mediante el componente JFontChooser
    jFontChooser1 = new JFontChooser(new Font("Arial", Font.BOLD, 12));
    if (jFontChooser1.showDialog(this, "Choix d'une police") == JFontChooser.ACCEPT_OPTION) {
      // se cambia la fuente de los caracteres del cuadro de texto
      txtTexte.setFont(jFontChooser1.getSelectedFont());
    }//si
  }

El cuadro de selección que muestra el método showDialog anterior es el siguiente:

Image

5.5. La aplicación gráfica IMPOTS

Retomamos la aplicación IMPOTS, que ya hemos tratado dos veces. Ahora le agregamos una interfaz gráfica:

Image

Los controles son los siguientes

n.º
tipo
nombre
función
1
JRadioButton
rdOui
marcar si está casado
2
JRadioButton
rdNon
marcar si no está casado
3
JSpinner
spinEnfants
número de hijos del contribuyente
Mínimo=0, Máximo=20, Incremento=1
4
JTextField
txtSalaire
salario anual del contribuyente en F
5
JLabel
lblImpots
monto del impuesto a pagar
6
JTextField
txtStatus
campo de mensajes de estado: no modificable

El menú es el siguiente:

opción principal
opción secundaria
nombre
función
Impuestos
   
 
Inicializar
mnuInitialiser
carga los datos necesarios para el cálculo a partir de un archivo de texto
 
Calcular
mnuCalculer
calcula el impuesto a pagar cuando todos los datos necesarios están presentes y son correctos
 
Borrar
mnuEffacer
restablece el formulario a su estado inicial
 
Salir
mnuQuitter
cierra la aplicación

Reglas de funcionamiento

  • el menú Calculer permanece desactivado mientras no haya nada en el campo del salario
  • si, al iniciar el cálculo, resulta que el salario es incorrecto, se reporta el error:

Image

A continuación se presenta el programa. Utiliza la clase impots creada en el capítulo sobre clases. Una parte del código generado automáticamente por JBuilder no se ha reproducido aquí.

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.filechooser.FileFilter;
import java.io.*;
import java.util.*;
import javax.swing.event.*;

public class frmImpots extends JFrame {
  // los componentes de la ventana
  JPanel contentPane;
  JMenuBar jMenuBar1 = new JMenuBar();
  JMenu jMenu1 = new JMenu();
  JMenuItem mnuInitialiser = new JMenuItem();
  JMenuItem mnuCalculer = new JMenuItem();
  JMenuItem mnuEffacer = new JMenuItem();
  JMenuItem mnuQuitter = new JMenuItem();
  JLabel jLabel1 = new JLabel();
  JFileChooser jFileChooser1 = new JFileChooser();
  JTextField txtStatus = new JTextField();
  JRadioButton rdOui = new JRadioButton();
  JRadioButton rdNon = new JRadioButton();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSalaire = new JTextField();
  JLabel jLabel4 = new JLabel();
  JLabel jLabel5 = new JLabel();
  JLabel lblImpots = new JLabel();
  JLabel jLabel7 = new JLabel();
  ButtonGroup buttonGroup1 = new ButtonGroup();
  JSpinner spinEnfants=null;
  FileFilter filtreTxt=null;

   // los atributos de la clase
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;

   //Crear el marco
  public frmImpots() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // otras inicializaciones
    moreInit();
  }

   // inicialización del formulario
  private void moreInit(){
     // menú «Calcular» desactivado
    mnuCalculer.setEnabled(false);
    // campos de entrada desactivados
    txtSalaire.setEditable(false);
    txtSalaire.setBackground(Color.WHITE);
    // campo de estado
    txtStatus.setBackground(Color.WHITE);
    // selector «Hijos»: entre 0 y 20 hijos
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);
     // filtro *.txt para el cuadro de selección
    filtreTxt = new javax.swing.filechooser.FileFilter(){
      public boolean accept(File f){
        // ¿Se acepta la letra «f»?
        return f.getName().toLowerCase().endsWith(".txt");
      }//aceptar
      public String getDescription(){
        // descripción del filtro
        return "Fichiers Texte (*.txt)";
      }//getDescription
    };
     // se agrega el filtro *.txt
    jFileChooser1.addChoosableFileFilter(filtreTxt);
    // también queremos el filtro para todos los archivos
    jFileChooser1.setAcceptAllFileFilterUsed(true);
    // se establece el directorio de origen del buzón FileChooser
    jFileChooser1.setCurrentDirectory(new File("."));
  }//moreInit

   //Inicializar el componente
  private void jbInit() throws Exception  {

................

  }

   //Reemplazado, así podemos salir cuando se cierre la ventana
  protected void processWindowEvent(WindowEvent e) {
.....................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // salimos de la aplicación
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // se carga el archivo de datos
     // que se selecciona con el cuadro de selección JFileChooser1
    jFileChooser1.setFileFilter(filtreTxt);
    if (jFileChooser1.showOpenDialog(this)!=JFileChooser.APPROVE_OPTION)
      return;
     // se procesa el archivo seleccionado
    try{
       // lectura de datos
      lireFichier(jFileChooser1.getSelectedFile());
       // creación del objeto de impuestos
      objImpots=new impots(limites,coeffr,coeffn);
       // confirmación
      txtStatus.setText("Données chargées");
       // el salario se puede modificar
      txtSalaire.setEditable(true);
       // No se pueden realizar más cambios
      mnuInitialiser.setEnabled(false);
    }catch(Exception ex){
       // problema
      txtStatus.setText("Erreur : " + ex.getMessage());
      // fin
      return;
    }//captura
  }

  private void lireFichier(File fichier) throws Exception {
     // las tablas de datos
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // apertura del archivo en modo de lectura
    BufferedReader IN=new BufferedReader(new FileReader(fichier));
    // se lee el archivo línea por línea
     // tienen la forma límite coeffr coeffn
    String ligne=null;
    int numLigne=0;           // N.º de línea actual
    while((ligne=IN.readLine())!=null){
      // una línea más
      numLigne++;
       // se descompone la línea en campos
      champs=ligne.split("\\s+");
       // ¿3 campos?
      if(champs.length!=3)
        throw new Exception("ligne " + numLigne + "erronée dans fichier des données");
       // se recuperan los tres campos
       aLimites.add(champs[0]);
       aCoeffR.add(champs[1]);
       aCoeffN.add(champs[2]);
    }//while
     // cierre del archivo
    IN.close();
     // transferencia de los datos a tablas delimitadas
    int n=aLimites.size();
    limites=new double[n];
    coeffr=new double[n];
    coeffn=new double[n];
    for(int i=0;i<n;i++){
      limites[i]=Double.parseDouble((String)aLimites.get(i));
      coeffr[i]=Double.parseDouble((String)aCoeffR.get(i));
      coeffn[i]=Double.parseDouble((String)aCoeffN.get(i));
    }//for
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // cálculo del impuesto
     // verificación del salario
    int salaire=0;
    try{
      salaire=Integer.parseInt(txtSalaire.getText().trim());
      if(salaire<0) throw new Exception();
    }catch (Exception ex){
       // mensaje de error
      txtStatus.setText("Salaire incorrect. Recommencez");
       // foco en campo con error
      txtSalaire.requestFocus();
       // regreso a la interfaz
      return;
    }
     // número de hijos
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // cálculo del impuesto
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),InbEnfants.intValue(),salaire));
     // borrar mensaje de estado
    txtStatus.setText("");
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
     // el salario ha cambiado: se actualiza el menú «Calcular»
    mnuCalculer.setEnabled(! txtSalaire.getText().trim().equals(""));
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
    // borrar el formulario
    rdNon.setSelected(true);
    spinEnfants.getModel().setValue(new Integer(0));
    txtSalaire.setText("");
    mnuCalculer.setEnabled(false);
    lblImpots.setText("");
  }
}

Aquí hemos utilizado un componente que está disponible a partir de la versión 1.4 de JDK: el JSpinner. Se trata de un incrementador, que en este caso permite al usuario establecer el número de hijos. Este componente Swing no estaba disponible en la barra de componentes Swing de JBuilder 6, utilizada para la prueba. Sin embargo, esto no impide su uso, aunque el proceso sea un poco más complicado que con los componentes disponibles en la barra de componentes. De hecho, no se puede colocar el componente JSpinner en el formulario durante el diseño. Hay que hacerlo en tiempo de ejecución. Veamos el código que lo hace:

     // Cargolista «Hijos»: entre 0 y 20 hijos
    spinEnfants=new JSpinner(new SpinnerNumberModel(0,0,20,1));
    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

La primera línea crea el componente JSpinner. Este componente puede utilizarse para diversas cosas y no solo como un incrementador de números enteros, como en este caso. El argumento del constructor JSpinner es, en este caso, un modelo de incrementador de números que acepta cuatro parámetros (valor, mínimo, máximo, incremento). El componente tiene la siguiente forma:

Image

valeur
valor inicial que se muestra en el componente
min
valor mínimo que se puede mostrar en el componente
max
valor máximo que se puede mostrar en el componente
incrément
valor de incremento del valor mostrado al usar las flechas arriba/abajo del componente

El valor del componente se obtiene mediante su método getValue, que devuelve un tipo Object. De ahí que se necesiten algunas conversiones de tipo para obtener el entero que necesitamos:

     // número de hijos
    Integer InbEnfants=(Integer)spinEnfants.getValue();
     // cálculo del impuesto
    lblImpots.setText(""+objImpots.calculer(rdOui.isSelected(),
      InbEnfants.intValue(),salaire));

Una vez definido el componente JSpinner, se coloca en la ventana:

    spinEnfants.setBounds(new Rectangle(137,60,40,27));
    contentPane.add(spinEnfants);

Antes que nada, el usuario debe utilizar la opción de menú Initialiser, que crea un objeto impots con el constructor

    public impots(double[] LIMITES, double[] COEFFR, double[] COEFFN) throws Exception

de la clase impots. Cabe recordar que esta clase se definió a modo de ejemplo en el capítulo sobre clases. Se puede consultar dicho capítulo si es necesario. Las tres tablas necesarias para el constructor se completan a partir del contenido de un archivo de texto con el siguiente formato:

12620.0
0
0
13190
0,05
631
15640
0,1
1290,5
24 740
0,15
2072,5
31 810
0,2
3309,5
39 970
0,25
4900
48 360
0,3
6898,5
55 790
0,35
9316,5
92 970
0,4
12106
127 860
0,45
16 754,5
151 250
0,50
23 147,5
172 040
0,55
30 710
195 000
0,60
39312
0
0,65
49062

Cada línea contiene tres números separados por al menos un espacio. El usuario selecciona este archivo de texto mediante un componente JFileChooser. Una vez creado el objeto de tipo impots, solo queda dejar que el usuario proporcione los tres datos que se necesitan: si está casado o no, número de hijos y salario anual, y llamar al método calculer de la clase impots. La operación se puede repetir varias veces. El objeto de tipo impots, por su parte, solo se crea una vez, al utilizar la opción Initialiser.

5.6. Programación de applets

5.6.1. Introducción

Cuando se ha escrito una aplicación con interfaz gráfica, es bastante sencillo convertirla en applet. Al estar almacenada en una máquina A, esta puede descargarse mediante un navegador web desde una máquina B a través de Internet. De esta manera, la aplicación inicial se comparte entre numerosos usuarios, y ahí radica el principal interés de convertir una aplicación en un applet. Sin embargo, no todas las aplicaciones pueden transformarse de esta manera: para no perjudicar al usuario que utiliza un applet en su navegador, el entorno del applet está regulado:

  • un applet no puede leer ni escribir en el disco del usuario
  • solo puede comunicarse con la computadora desde la cual fue descargada por el navegador.

Estas son restricciones importantes. Implican, por ejemplo, que una aplicación que necesite leer información de un archivo o una base de datos deberá solicitarla a través de una aplicación intermediaria ubicada en el servidor desde donde se descargó.

La estructura general de una aplicación web sencilla es la siguiente:

Image

  • el cliente solicita un documento HTML al servidor web, generalmente mediante un navegador. Este documento puede contener un applet que funcionará como una aplicación gráfica independiente dentro del documento HTML que muestra el navegador del cliente.
  • Este applet podrá acceder a datos, pero solo a aquellos que se encuentren en el servidor web. No tendrá acceso ni a los recursos de la máquina cliente en la que se ejecuta ni a los de otras máquinas de la red, salvo aquella desde la cual se descargó.

5.6.2. La clase JApplet

5.6.2.1. Définition

Una aplicación puede descargarse mediante un navegador web si es una instancia de la clase java.applet.Applet o de la clase javax.swing.JApplet. Esta última deriva de la primera, la cual a su vez deriva de la clase Panel, que a su vez deriva de la clase Container. Una instancia de Applet o JApplet, al ser de tipo container, podrá contener componentes (Component) tales como botones, casillas de selección, listas, etc. Veamos algunas indicaciones sobre la función de los distintos métodos:

Método
Función
public void destroy();
destruye la instancia del applet
public AppletContext getAppletContext();
obtiene el contexto de ejecución del applet (el documento HTML en el que se encuentra, otros applets del mismo documento, …)
public String getAppletInfo();
devuelve una cadena de caracteres que proporciona información sobre el applet
public AudioClip getAudioClip(URL url);
carga el archivo de audio especificado por URL
public AudioClip getAudioClip(URL url, String name);
carga el archivo de audio especificado por URL/name
public URL getCodeBase();
devuelve el URL del applet
public URL getDocumentBase();
devuelve el URL del documento HTML que contiene el applet
public Image getImage(URL url);
obtiene la imagen especificada por URL
public Image getImage(URL url, String name);
obtiene la imagen especificada por URL/name
public String getParameter(String name);
obtiene el valor del parámetro name contenido en la etiqueta <applet> del documento HTML que contiene el applet.
public void init();
Este método es invocado por el navegador al iniciar el applet por primera vez
public boolean isActive();
Estado del applet
public void play(URL url);
reproduce el archivo de audio especificado por URL
public void play(URL url, String nombre);
reproduce el archivo de sonido especificado por UR/name
public void resize(Dimension d);
establece el tamaño del marco del applet
public void resize(int width, int height);
lo mismo
public final void setStub(AppletStub stub);
 
public void showStatus(String msg);
muestra un mensaje en la barra de estado del applet
public void start();
el navegador ejecuta este método cada vez que se muestra el documento que contiene el applet
public void stop();
el navegador ejecuta este método cada vez que se abandona el documento que contiene el applet para pasar a otro (cambio de URL por parte del usuario)

La clase JApplet ha aportado algunas mejoras a la clase Applet, en particular la capacidad de contener componentes JMenuBar y c.a.d. de los menús, lo cual no era posible con la clase Applet.

5.6.2.2. Ejecución de un applet: los métodos init, start y stop

Cuando un navegador carga un applet, invoca tres métodos del mismo:

init
Este método se invoca durante la carga inicial del applet. Por lo tanto, aquí se colocarán las inicializaciones necesarias para la aplicación.
start
Este método se invoca cada vez que el documento que contiene el applet se convierte en el documento activo del navegador. Así, cuando un usuario carga un applet, los métodos init y start se ejecutarán en ese orden. Cuando salga del documento para visualizar otro, se ejecutará el método stop. Cuando regrese a él más tarde, se ejecutará el método start.
stop
Este método se invoca cada vez que el usuario sale del documento que contiene el applet.

Para muchos applets, solo se necesita el método init. Los métodos start y stop solo son necesarios si la aplicación inicia tareas (hilos) que se ejecutan en paralelo y de manera continua, a menudo sin que el usuario se dé cuenta. Cuando el usuario sale del documento, la parte visible de la aplicación desaparece, pero estas tareas en segundo plano siguen funcionando. Esto suele ser innecesario. Por lo tanto, se aprovecha la llamada del navegador al método stop para detenerlas. Si el usuario regresa al documento, se aprovecha la llamada del navegador al método start para reiniciarlas.

Tomemos, por ejemplo, un applet que tiene un reloj en su interfaz gráfica. Este reloj se mantiene mediante una tarea en segundo plano (hilo). Cuando el usuario sale de la página del applet en el navegador, no tiene sentido mantener el reloj, que ya se ha vuelto invisible: en el método stop del applet, detendremos el hilo que administra el reloj. En el método **start**, se reiniciará para que, cuando el usuario regrese a la página del applet, encuentre un reloj que marque la hora correcta.

5.6.3. Transformación de una aplicación gráfica en un applet

Suponemos aquí que esta transformación es posible, es decir, que cumple con las restricciones de ejecución de los applets. Una aplicación se inicia mediante el método main de una de sus clases:


public class application{
    
    public static main void(String arg[]){
        
    }
    
}// fin de categoría

Una aplicación de este tipo se transforma en un applet de la siguiente manera:

import java.applet.JApplet;

public class application extends JApplet{
    
    public void init(){
        
    }
    
}// fin de clase

Cabe destacar lo siguiente:

  1. la clase application ahora deriva de la clase JApplet
  2. el método main se reemplaza por el método init.

A modo de ejemplo, volvemos a una aplicación que ya hemos analizado: la gestión de listas.

Image

Los componentes de esta ventana son los siguientes:

n.º
tipo
nombre
función
1
JTextField
txtSaisie
campo de entrada
2
JList
jList1
lista contenida en un contenedor jScrollPane1
3
JList
jList2
lista contenida en un contenedor jScrollPane2
4
JButton
cmd1To2
transfiere los elementos seleccionados de la lista 1 a la lista 2
5
JButton
cmd2To1
hace lo contrario
6
JButton
cmdRaz1
vacía la lista 1
7
JButton
cmdRaz2
vacía la lista 2

La estructura de la aplicación era la siguiente:

public class interfaceAppli extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Crear el marco*/
  public interfaceAppli() {
    enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    ...
    txtSaisie.addActionListener(new java.awt.event.ActionListener() {
      public void actionPerformed(ActionEvent e) {
        txtSaisie_actionPerformed(e);
      }
    });
        ...
         // Jlist1 se coloca en el contenedor jScrollPane1
    jScrollPane1.getViewport().add(jList1, null);
        // Jlist2 se coloca en el contenedor jScrollPane2
    jScrollPane2.getViewport().add(jList2, null);
        ...
  }
   /**Reemplazado, para que podamos salir cuando se cierre la ventana*/
  protected void processWindowEvent(WindowEvent e) {
...
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
.............
}//clase
  void cmd1To2_actionPerformed(ActionEvent e) {
..........
  }//transferencia
  void cmdRaz1_actionPerformed(ActionEvent e) {
    // vaciar lista 1
    v1.removeAllElements();
  }//comando Borrar1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // borrar lista 2
    v2.removeAllElements();
  }///comando Borrar2

Para transformar la clase appli en applet, se debe proceder de la siguiente manera:

  • modificar la clase interfaceAppli anterior para que ya no se derive de JFrame, sino de JApplet:
public class interfaceAppli extends JApplet {
  • eliminar la instrucción que establece el título de la ventana JFrame. Un applet JApplet no tiene barra de título
    // this.setTitle("JList");
  • Cambiar el constructor por un método init y, en ese método, eliminar el manejo de eventos de ventana (WindowListener, ...). Un applet es un contenedor que no se puede redimensionar ni cerrar.
   /**Construir el marco*/
  public init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli
  • El método processWindowEvent debe eliminarse o ponerse en comentarios
   /**Reemplazado, para que podamos salir cuando se cierre la ventana*/
  //protected void processWindowEvent(WindowEvent e) {
  //  super.processWindowEvent(e);
  //  si (e.getID() == WindowEvent.WINDOW_CLOSING) {
  //    System.exit(0);
  //  }
  // }

A modo de ejemplo, se presenta el código completo del applet, excepto la parte generada automáticamente por JBuilder

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceAppli extends JApplet {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JLabel jLabel2 = new JLabel();
  JLabel jLabel3 = new JLabel();
  JTextField txtSaisie = new JTextField();
  JButton cmd1To2 = new JButton();
  JButton cmd2To1 = new JButton();
  DefaultListModel v1=new DefaultListModel();
  DefaultListModel v2=new DefaultListModel();
  JList jList1 = new JList(v1);
  JList jList2 = new JList(v2);
  JScrollPane jScrollPane1 = new JScrollPane();
  JScrollPane jScrollPane2 = new JScrollPane();
  JButton cmdRaz1 = new JButton();
  JButton cmdRaz2 = new JButton();
  JLabel jLabel4 = new JLabel();

   /**Construir el marco*/
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
  }//interfaceAppli

   /**Inicializar el componente*/
  private void jbInit() throws Exception  {
    //setIconImage(Toolkit.getDefaultToolkit().createImage(interfaceAppli.class.getResource("[Votre icône]")));
    contentPane = (JPanel) this.getContentPane();
    contentPane.setLayout(null);
    this.setSize(new Dimension(400, 308));
    // this.setTitle("JList");
    jScrollPane1.setBounds(new Rectangle(37, 133, 124, 101));
    jScrollPane2.setBounds(new Rectangle(232, 132, 124, 101));
.............
  }

  void txtSaisie_actionPerformed(ActionEvent e) {
     // el texto ingresado ha sido validado
     // se recupera sin los espacios iniciales y finales
    String texte=txtSaisie.getText().trim();
     // si está vacío, no lo queremos
    if(texte.equals("")){
      // mensaje de error
      JOptionPane.showMessageDialog(this,"Vous devez taper un texte",
        "Erreur",JOptionPane.WARNING_MESSAGE);
      // fin
      return;
    }//si
    // si no está vacío, lo agregamos a los valores de la lista 1
    v1.addElement(texte);
     // y se vacía el campo de entrada
    txtSaisie.setText("");
  }

  void cmd1To2_actionPerformed(ActionEvent e) {
    // se transfieren los elementos seleccionados de la lista 1 a la lista 2
    transfert(jList1,jList2);
  }//cmd1To2

  private void transfert(JList L1, JList L2){
      // transferencia de los elementos seleccionados de la lista 1 a la lista 2
       // se recupera la tabla de índices de los elementos seleccionados en L1
      int[] indices=L1.getSelectedIndices();
      // ¿Hay algo que hacer?
      if (indices.length==0) return;
      // se recuperan los valores de L1
      DefaultListModel v1=(DefaultListModel)L1.getModel();
      // y los de L2
      DefaultListModel v2=(DefaultListModel)L2.getModel();
      for(int i=indices.length-1;i>=0;i--){
        // se agregan a L2 los valores seleccionados en L1
        v2.addElement(v1.elementAt(indices[i]));
        // los elementos de L1 copiados en L2 deben eliminarse de L1
        v1.removeElementAt(indices[i]);
      }//para
  }//transferencia

  private void affiche(String message){
    // muestra un mensaje
      JOptionPane.showMessageDialog(this,message,
        "Suivi",JOptionPane.INFORMATION_MESSAGE);
  }// muestra

  void cmd2To1_actionPerformed(ActionEvent e) {
    // transfiere los elementos seleccionados de jList2 a jList1
      transfert(jList2,jList1);
  }//cmd2TO1

  void cmdRaz1_actionPerformed(ActionEvent e) {
    // vacía la lista 1
    v1.removeAllElements();
  }//comando Raz1

  void cmdRaz2_actionPerformed(ActionEvent e) {
    // borrar lista 2
    v2.removeAllElements();
  }//comando Borrar2

}//clase

Se puede compilar el código fuente de este applet. Aquí lo hacemos con el JDK, sin el JBuilder.

E:\data\serge\Jbuilder\interfaces\JApplets\1>javac.bat interfaceAppli.java

E:\data\serge\Jbuilder\interfaces\JApplets\1>dir
12/06/2002  16:40                6 148 interfaceAppli.java
12/06/2002  16:41                  527 interfaceAppli$1.class
12/06/2002  16:41                  525 interfaceAppli$2.class
12/06/2002  16:41                  525 interfaceAppli$3.class
12/06/2002  16:41                  525 interfaceAppli$4.class
12/06/2002  16:41                  525 interfaceAppli$5.class
12/06/2002  16:41                4 759 interfaceAppli.class

La aplicación se puede probar con el programa AppletViewer de JDK, que permite ejecutar applets o un navegador. Para ello, hay que crear el documento HTML appli.htm, que contendrá el applet:

<html>
    <head>
        <title>listes swing</title>
    </head>
    <body>
        <applet 
        code="interfaceAppli.class"
      width="400"
      height="300">
        </applet>
    </body>
</html>

Aquí tenemos un documento HTML clásico, salvo por la presencia de la etiqueta applet. Esta se utilizó con tres parámetros:

code="interfaceAppli.class"
nombre de la clase JAVA compilada que se cargará para ejecutar el applet
width="400"
ancho del marco del applet en el documento
height="300"
altura del marco del applet en el documento

Una vez que se ha escrito el archivo appli.htm, se puede cargar con el programa appletviewer de JDK o con un navegador. En una ventana de DOS, se escribe el siguiente comando en la carpeta del archivo appli.htm:

appletviewer appli.htm

Aquí se supone que el directorio del ejecutable appletviewer.exe se encuentra en el directorio PATH de la ventana de DOS; de lo contrario, habría que indicar la ruta completa del ejecutable appletviewer.exe. Aparecerá la siguiente ventana:

Image

Detendremos la ejecución del applet con la opción Applet/Quitter. Ahora probemos el applet con un navegador. Este debe utilizar una máquina virtual Java 2 para poder mostrar los componentes Swing. Hasta hace poco (2001), esta restricción planteaba un problema, ya que Sun producía JDK que los desarrolladores de navegadores solo incorporaban con mucho retraso. Finalmente, Sun eliminó este obstáculo al poner a disposición de los usuarios una aplicación llamada «Java plugin», que permite que los navegadores Internet Explorer y Netscape Navigator utilicen las versiones más recientes de JRE producidas por Sun (JRE = Java Runtime Environment). Las pruebas que siguen se realizaron con IE 5.5, equipado con el plugin de Java 1.4.

Una primera forma de probar el applet interfaceAppli.class es cargar el archivo HTML appli.htm directamente en el navegador haciendo doble clic sobre él. El navegador mostrará entonces la página HTML y su applet sin necesidad de un servidor web:

Image

Se puede observar en el URL (1) que el archivo se cargó directamente en el navegador. En el siguiente ejemplo, el archivo appli.htm se solicitó a un servidor web Apache que opera en el puerto 81 de la máquina local:

Image

5.6.4. La opción de formato <applet> en un documento HTML

Hemos visto que, dentro de un documento HTML, el applet se referencia mediante la etiqueta de formato <applet>. Esta etiqueta puede tener varios parámetros:

<applet
    code=
    width=
    height=
    codebase=
    align=
    hspace=
    vspace=
alt=
>
    <param name1=nom1 value=val1>
    <param name2=nom2 value=val2>
    texte
>
</applet>

El significado de los parámetros es el siguiente:

Parámetro
Significado
code
obligatorio: nombre del archivo .class que se ejecutará
width
obligatorio: ancho del applet en el documento
height
obligatorio - altura …
codebase
opcional: URL del directorio que contiene el applet a ejecutar. Si no se especifica codebase, el applet se buscará en el directorio del documento HTML que lo referencia
align
opcional - posicionamiento (LEFT, RiGHT, CENTER) del applet en el documento
hspace
opcional: margen horizontal que rodea el applet, expresado en píxeles
vspace
opcional: margen vertical que rodea el applet, expresado en píxeles
alt
opcional: texto que se muestra en lugar del applet si el navegador no puede cargarlo
param
opcional: parámetro pasado al applet que especifica su nombre (name) y su valor (value). El applet podrá recuperar el valor del parámetro nombre1 mediante val1=getParameter("nombre1")
Se pueden usar tantos parámetros como se desee
texte
opcional: se mostrará en cualquier navegador que no pueda ejecutar un applet, por ejemplo, porque no cuenta con una máquina virtual Java.

Veamos un ejemplo para ilustrar cómo pasar parámetros a un applet:

<html>
    <head>
        <title>paramètres applet</title>
    </head>
    <body>
        <applet code="interfaceParams.class" width="400" height="300">
      <param name="param1" value="val1">
      <param name="param2" value="val2">      
        </applet>
    </body>
</html>

El código Java del applet interfaceParams se generó tal como se indicó anteriormente. Se creó una aplicación JBuilder y luego se realizaron las transformaciones mencionadas anteriormente:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;

public class interfaceParams extends JApplet {
  JPanel contentPane;
  JScrollPane jScrollPane1 = new JScrollPane();
  JLabel jLabel1 = new JLabel();
  DefaultListModel params=new DefaultListModel();
  JList lstParams = new JList(params);

  //Construir el marco
  public void init() {
    // enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // otras inicializaciones
    moreInit();
  }

   // inicializaciones
  public void moreInit(){
     // muestra los valores de los parámetros del applet
    params.addElement("nom=param1 valeur="+getParameter("param1"));
    params.addElement("nom=param2 valeur="+getParameter("param2"));
  }//más Init

   //Inicializar el componente
  private void jbInit() throws Exception  {
............
    this.setSize(new Dimension(205, 156));
    //this.setTitle("Parámetros de un applet");
    jScrollPane1.setBounds(new Rectangle(19, 53, 160, 73));
............
 }
}

La ejecución con AppletViewer:

Image

5.6.5. Acceder a recursos remotos desde un applet

Muchas aplicaciones necesitan aprovechar la información contenida en archivos o bases de datos. Ya hemos señalado que un applet no tiene acceso a los recursos de la máquina en la que se ejecuta. Es una medida de sentido común. De lo contrario, bastaría con escribir un applet para «espiar» el disco de quienes lo cargan. Sin embargo, el applet sí tiene acceso a los recursos del servidor desde el cual se descargó, por ejemplo, a los archivos. Eso es lo que veremos ahora.

5.6.5.1. La clase URL

Cualquier aplicación Java puede leer un archivo que se encuentre en una máquina de la red gracias a la clase java.net.URL (URL = Uniform Resource Locator). Un URL identifica un recurso de la red, la máquina en la que se encuentra, así como el protocolo y el puerto de comunicación que se deben utilizar para recuperarlo, en el formato:

protocolo:puerto//máquina/archivo

Así, el URL http://www.ibm.com/index.html designa el archivo index.html de la máquina www.ibm.com. Se puede acceder a él mediante el protocolo http. No se especifica el puerto: el navegador utilizará el puerto 80, que es el puerto predeterminado del servicio http.

Veamos en detalle algunos de los elementos de la clase URL:

public URL(String spec)
crea una instancia de URL a partir de una cadena del tipo «protocolo:puerto//máquina/archivo»; lanza una excepción si la sintaxis de la cadena no corresponde a un URL
  
public String getFile()
permite obtener el campo «archivo» de la cadena «protocolo:puerto//máquina/archivo» de URL
  
public String getHost()
permite obtener el campo «máquina» de la cadena «protocolo:puerto//máquina/archivo» del URL
  
public String getPort()
permite obtener el campo «puerto» de la cadena «protocolo:puerto//máquina/archivo» del URL
  
public String getProtocol()
permite obtener el campo «protocolo» de la cadena «protocolo:puerto//máquina/archivo» del URL
  
public URLConnection openConnection()
abre la conexión con la máquina remota getHost() en su puerto getPort() según el protocolo getProtocol() con el fin de leer el archivo getFile(). Lanza una excepción si no se pudo abrir la conexión
  
public final InputStream openStream()
Abreviatura de openConnection().getInputStream(). Permite obtener un flujo de entrada a partir del cual se podrá leer el contenido del archivo getFile(). Lanza una excepción si no se pudo obtener el flujo
  
public String toString()
muestra la identidad de la instancia de URL

Aquí hay dos métodos que nos interesan:

  • public URL(String spec) para especificar el archivo que se va a procesar
  • public final InputStream openStream() para procesarlo

5.6.5.2. Un ejemplo de consola

Vamos a escribir un programa en Java, sin interfaz gráfica, encargado de mostrar en pantalla el contenido de un URL que se le pase como parámetro. Una llamada de ejemplo podría ser la siguiente:

    DOS> java urlcontenu http://istia.univ-angers.fr/index.html

El programa es relativamente sencillo:


import java.net.*;             // para la clase URL
import java.io.*;                // para los flujos (stream)

public class urlcontenu{

// muestra el contenido de URL pasado como argumento
// este contenido debe ser texto para que sea legible

  public static void main (String arg[]){
    // verificación de los argumentos
    if(arg.length==0){
      System.err.println("Syntaxe pg url");
      System.exit(0);
    }
    
    try{
      // creación de URL      
      URL url=new URL(arg[0]);
      // lectura del contenido
      try{
        // creación del flujo de entrada
        BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));
        try{
          // lectura de las líneas de texto en el flujo de entrada
          String ligne;
          while((ligne=is.readLine())!=null)
            System.out.println(ligne);
        } catch (Exception e){
            System.err.println("Erreur lecture : " +e);
        }
        finally{
          try { is.close(); } catch (Exception e) {}
        }
      } catch (Exception e){
          System.err.println("Erreur openStream : " +e);
      }
    } catch (Exception e){
      System.err.println("Erreur création URL : " +e);
    }
  }// fin de main
}// fin de clase

Después de verificar que sí había un argumento, intentamos crear un URL con este:


// creación del URL      
      URL url=new URL(arg[0]);

Esta creación puede fallar si el argumento no respeta la sintaxis de los URL protocole:port//machine/fichier. Si se cuenta con un URL sintácticamente correcto, se intenta crear un flujo de entrada a partir del cual se puedan leer líneas de texto. El flujo de entrada proporcionado por URL URL.openStream() proporciona un flujo de tipo InputStream, que es un flujo orientado a caracteres: la lectura se realiza carácter por carácter y hay que formar las líneas uno mismo. Para poder leer líneas de texto, hay que utilizar el método readLine de las clases BufferedReader o DataInputStream.On; en este caso se ha elegido BufferedReader. Solo nos queda transformar el flujo InputStream de URL en el flujo BufferedReader. Esto se hace creando un flujo intermedio InputStreamReader:


BufferedReader is=new BufferedReader(new InputStreamReader(url.openStream()));

La creación de este flujo puede fallar. Se maneja la excepción correspondiente. Una vez obtenido el flujo, solo nos queda leer las líneas de texto y mostrarlas en pantalla.


            String ligne;
         while((ligne=is.readLine())!=null)
                System.out.println(ligne);

Una vez más, la lectura puede generar una excepción que debe gestionarse. A continuación se muestra un ejemplo de ejecución del programa que requiere un archivo URL local:

E:\data\serge\Jbuilder\interfaces\JApplets\3>java urlcontenu http://localhost
<html>

<head>


<title>Bienvenue dans le Serveur Web personnel</title>
</head>

<body bgcolor="#FFFFFF" link="#0080FF" vlink="#0080FF"
topmargin="0" leftmargin="0">

<table border="0" cellpadding="0" cellspacing="0" width="100%"
bgcolor="#000000">
............
                </table>
                </center></div></td>
            </tr>
        </table>
        </td>
    </tr>
</table>
</body>
</html>

5.6.5.3. Un ejemplo gráfico

La interfaz gráfica será la siguiente:

Image

Número
Nombre
Tipo
Función
1
txtURL
JTextField
URL para leer
2
btnCharger
JButton
Botón para iniciar la reproducción de URL
3
JScrollPane1
JScrollPane
panel deslizante
4
lstURL
JList
lista que muestra el contenido del URL solicitado

Al ejecutarlo, obtenemos un resultado similar al del programa de consola:

Image

El código relevante de la aplicación es el siguiente:

import java.awt.*;
import java.awt.event.*;
import javax.swing.*;
import javax.swing.event.*;
import java.net.*;
import java.io.*;

public class interfaceURL extends JFrame {
  JPanel contentPane;
  JLabel jLabel1 = new JLabel();
  JTextField txtURL = new JTextField();
  JButton btnCharger = new JButton();
  JScrollPane jScrollPane1 = new JScrollPane();
  DefaultListModel lignes=new DefaultListModel();
  JList lstURL = new JList(lignes);

  //Construir el marco
  public interfaceURL() {
..............
  }

   //Inicializar el componente
  private void jbInit() throws Exception  {
..............
  }

   //Reemplazado, así podemos salir cuando se cierre la ventana
  protected void processWindowEvent(WindowEvent e) {
...................
  }

  void txtURL_caretUpdate(CaretEvent e) {
    // establece el estado del botón Cargar
    btnCharger.setEnabled(! txtURL.getText().trim().equals(""));
  }

  void btnCharger_actionPerformed(ActionEvent e) {
    // muestra el contenido de URL en la lista
    try{
      afficherURL(txtURL.getText().trim());
    }catch(Exception ex){
       // muestra un error
      JOptionPane.showMessageDialog(this,"Erreur : " + ex.getMessage(),"Erreur",JOptionPane.ERROR_MESSAGE);
    }//try-catch
  }

  private void afficherURL(String strURL) throws Exception {
    // muestra el contenido de URL y strURL en la lista
     // No se maneja ninguna excepción específicamente. Simplemente se reenvían

     // creación del URL
    URL url=new URL(strURL);
     // creación del flujo de entrada
    BufferedReader IN=new BufferedReader(new InputStreamReader(url.openStream()));
    // lectura de las líneas de texto en el flujo de entrada
    String ligne;
    while((ligne=IN.readLine())!=null)
      lignes.addElement(ligne);
     // cierre del flujo de lectura
    IN.close();
  }
}

5.6.5.4. Un applet

La aplicación gráfica anterior se transforma en un applet, tal como se ha mostrado en varias ocasiones. El applet se inserta en un documento HTML appliURL.htm:

<html>
  <head>
    <title>Applet lisant une URL</title>
  </head>
  <body>
    <h1>Applet lisant une URL</h1>
    <applet
      code="appletURL.class"
      width="400"
      height="300"
    >
    </applet>
  </body>
</html>

Image

En el ejemplo anterior, el navegador solicitó el archivo URL http://localhost:81/Japplets/2/appliURL.htm a un servidor web apache que opera en el puerto 81. A continuación, el applet se mostró en el navegador. En ella, se volvió a solicitar el archivo URL http://localhost:81/Japplets/2/appliURL.htm para verificar que se obtuviera efectivamente el archivo appliURL.htm que habíamos creado. Ahora intentemos cargar un archivo URL que no pertenezca a la máquina que generó el applet (en este caso, localhost):

Image

Se rechazó la carga del archivo URL. Aquí nos encontramos con la restricción propia de los applets: solo pueden acceder a los recursos de red de la máquina desde la que se descargaron. Existe una forma de que el applet eluda esta restricción: delegar las solicitudes de red a un programa servidor ubicado en la máquina desde la que se descargó. Este programa realizará las solicitudes de red en lugar del applet y le enviará los resultados. A esto se le llama un programa relé.

5.7. El applet IMPOTS

Ahora vamos a convertir la aplicación gráfica IMPOTS en un applet. Esto tiene cierto interés: la aplicación estará disponible para cualquier usuario de Internet que cuente con un navegador y un complemento de Java 1.4 (gracias al componente JSpinner). De esta manera, nuestra aplicación se vuelve global... Esta modificación requerirá algo más que la simple transformación de aplicación gráfica a applet, que ya se ha vuelto un procedimiento clásico. La aplicación utiliza una opción de menú Initialiser cuyo objetivo es leer el contenido de un archivo local. Sin embargo, si imaginamos una aplicación web, vemos que este esquema ya no es válido:

Image

Es evidente que los datos que definen las escalas impositivas estarán en el servidor web y no en cada una de las máquinas clientas. El archivo que se debe leer en el servidor web se colocará aquí en la misma carpeta que el applet, y la opción Initialiser deberá buscarlo allí. Los ejemplos anteriores han mostrado cómo hacerlo. Por otra parte, para seleccionar el archivo de datos localmente, se había utilizado un componente JFileChooser que ya no es necesario aquí.

El documento HTML que contiene el applet será el siguiente:

<html>
  <head>
    <title>Applet de calcul d'impôts</title>
  </head>
  <body>
    <h2>Calcul d'impôts</h2>
    <applet
      code="appletImpots.class"
      width="320"
      height="270"
    >

<param name="data" value="impots.txt">


    </applet>
  </body>
</html>

Cabe destacar el parámetro data, cuyo valor es el nombre del archivo que contiene los datos de la tabla de impuestos. El documento HTML, la clase appletImpots, la clase impots y el archivo impots.txt se encuentran todos en la misma carpeta del servidor web:

E:\data\serge\web\JApplets\impots>dir
12/06/2002  13:24                  247 impots.txt
13/06/2002  10:17                  654 appletImpots$2.class
13/06/2002  10:17                  653 appletImpots$3.class
13/06/2002  10:17                  653 appletImpots$4.class
13/06/2002  10:17                  651 appletImpots$5.class
13/06/2002  10:06                  651 appletImpots$6.class
13/06/2002  10:17                8 655 appletImpots.class
13/06/2002  10:17                  657 appletImpots$1.class
13/06/2002  10:24                  286 appletImpots.htm
13/06/2002  10:17                1 305 impots.class

El código del applet es el siguiente (solo hemos resaltado los cambios con respecto a la aplicación gráfica):

...........
import java.net.*;
import java.applet.Applet;

public class appletImpots extends JApplet {
  // los componentes de la ventana
  JPanel contentPane;
............................

   // los atributos de la clase
  double[] limites=null;
  double[] coeffr=null;
  double[] coeffn=null;
  impots objImpots=null;
  String urlDATA=null;

  //Crear el marco
  public void init() {
    //enableEvents(AWTEvent.WINDOW_EVENT_MASK);
    try {
      jbInit();
    }
    catch(Exception e) {
      e.printStackTrace();
    }
     // otras inicializaciones
    moreInit();
  }

   // inicialización del formulario
  private void moreInit(){
     // menú «Calcular» desactivado
    mnuCalculer.setEnabled(false);
................
     // se recupera el nombre del archivo de la tabla de impuestos
    String nomFichier=getParameter("data");
    // ¿Error?
    if(nomFichier==null){
       // mensaje de error
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // se bloquea la opción «Inicializar»
      mnuInitialiser.setEnabled(false);
      // fin
      return;
    }//si
     // se establece el URL de los datos
    urlDATA=getCodeBase()+"/"+nomFichier;
  }//moreInit

   //Inicializar el componente
  private void jbInit() throws Exception  {
...................
  }

  void mnuQuitter_actionPerformed(ActionEvent e) {
    // Se sale de la aplicación
    System.exit(0);
  }

  void mnuInitialiser_actionPerformed(ActionEvent e) {
    // se carga el archivo de datos
    try{
       // lectura de datos
      lireDATA();
       // creación del objeto «impuestos»
      objImpots=new impots(limites,coeffr,coeffn);
................
  }

  private void lireDATA() throws Exception {
     // las tablas de datos
    ArrayList aLimites=new ArrayList();
    ArrayList aCoeffR=new ArrayList();
    ArrayList aCoeffN=new ArrayList();
    String[] champs=null;

     // se abre el archivo en modo de lectura
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));
    // se lee el archivo línea por línea
....................
  }

  void mnuCalculer_actionPerformed(ActionEvent e) {
    // cálculo del impuesto
......................
  }

  void txtSalaire_caretUpdate(CaretEvent e) {
..........
  }

  void mnuEffacer_actionPerformed(ActionEvent e) {
...............
  }
}

Aquí solo comentamos los cambios que se deben a que el archivo de datos que se va a leer ahora se encuentra en una máquina remota en lugar de en una máquina local:

El nombre del archivo de datos a leer, URL, se obtiene mediante el siguiente código:

     // se recupera el nombre del archivo de la tabla de impuestos
    String nomFichier=getParameter("data");
    // ¿Error?
    if(nomFichier==null){
       // mensaje de error
      txtStatus.setText("Le paramètre data de l'applet n'a pas été initialisé");
       // se desactiva la opción «Inicializar»
      mnuInitialiser.setEnabled(false);
      // fin
      return;
    }//si
     // se establece el URL de los datos
    urlDATA=getCodeBase()+"/"+nomFichier;

Recordemos que el nombre del archivo «impots.txt» se pasó al parámetro data del applet:

    <param name="data" value="impots.txt">

Por lo tanto, el código anterior comienza por recuperar el valor del parámetro data, gestionando cualquier error que pueda surgir. Si el URL del documento HTML que contiene el applet es http://localhost:81/JApplets/impots/appletImpots.htm, el URL del archivo impots.txt será http://localhost:81/JApplets/impots/impots.txt. Necesitamos generar el nombre de este URL. El método getCodeBase() del applet devuelve el URL de la carpeta de donde se recuperó el documento HTML que contiene el applet, por lo que en nuestro ejemplo es http://localhost:81/JApplets/impots. La siguiente instrucción permite, por lo tanto, construir el URL del archivo de datos:

    urlDATA=getCodeBase()+"/"+nomFichier;

En el método lireFichier(), que lee el contenido de URL y urlData, se encuentra la creación del flujo de entrada que permitirá leer los datos:

     // apertura del archivo en modo de lectura
    BufferedReader IN=new BufferedReader(new InputStreamReader(new URL(urlDATA).openStream()));

A partir de ahí, ya no se puede distinguir si los datos provienen de un archivo remoto o local. A continuación se muestra un ejemplo de ejecución del applet:

Image

5.8. Conclusión

En este capítulo se ha presentado

  • una introducción a la creación de interfaces gráficas con JBuilder
  • los componentes Swing más comunes
  • la creación de applets

Recordemos que

  • el código generado por JBuilder se puede escribir a mano. Una vez obtenido este código de una forma u otra, basta con un simple JDK para ejecutarlo y JBuilder ya no es indispensable.
  • el uso de una herramienta como JBuilder puede generar importantes ganancias de productividad:
    • si bien es posible escribir a mano el código generado por JBuilder, esto puede llevar mucho tiempo y tiene poco interés, ya que la lógica de la aplicación suele estar en otra parte.
    • El código generado puede ser instructivo. Leerlo y estudiarlo es una buena forma de descubrir ciertos métodos y propiedades de los componentes que se utilizan por primera vez.
    • JBuilder es multiplataforma. Por lo tanto, se conserva lo aprendido al pasar de una plataforma a otra. Poder escribir programas que funcionen tanto en Windows como en Linux es, por supuesto, un factor de productividad muy importante. Pero esto se debe a Java en sí mismo y no a JBuilder.

5.9. JBuilder en Linux

Todos los ejemplos anteriores se han probado en Windows 98. Cabe preguntarse si los programas escritos son portables tal cual a Linux. Siempre y cuando la máquina con Linux en cuestión cuente con las clases utilizadas por los distintos programas, sí lo son. Si, por ejemplo, has instalado JBuilder en Linux, las clases necesarias ya se encuentran en tu máquina. A continuación se muestra, por ejemplo, el resultado de ejecutar uno de nuestros programas en el componente JList con JBuilder 4 en Linux:

A continuación, te mostramos cómo instalar JBuilder 4 Foundation en una máquina con Linux. Su instalación en una máquina con Win9x no presenta ningún problema y es similar al proceso que se describirá a continuación. Es probable que la instalación de versiones posteriores sea diferente, pero este documento puede, no obstante, ofrecerte información útil.

JBuilder está disponible en el sitio web de Inprise en la URL http://www.inprise.com/jbuilder

Image

En esta página se encuentran los enlaces para Windows y Linux, entre otros. A continuación, describimos la instalación de JBuilder en una máquina con Linux que cuenta con la interfaz gráfica KDE.

Al seguir el enlace «JBuilder 4 para Linux», aparece un formulario. Lo completamos y, al final, obtenemos dos archivos:

jb4docs_fr.tar.gz: la documentación y los ejemplos de JBuilder 4

jb4fndlinux_fr.tar.gz: JBuilder 4 Foundation. Se trata de una versión limitada del JBuilder 4 comercial, pero suficiente para fines educativos.

Se te enviará por correo electrónico una clave de activación del software. Esta te permitirá utilizar JBuilder 4 y se te solicitará la primera vez que lo uses. Si pierdes esta clave, puedes volver a la URL anterior y seguir el enlace «get your activation key». A partir de aquí, suponemos que eres root y que te encuentras en el directorio de los dos archivos tar.gz mencionados anteriormente. Descomprime los dos archivos:

[tar xvzf jb4fndlinux_fr.tar.gz]
[tar xvzf jb4docs_fr.tar.gz]
[ls -l]
drwxr-xr-x    3 nobody   nobody       4096 oct 10  2000 docs
drwxr-xr-x    3 nobody   nobody       4096 déc  5 13:00 foundation
[ls -l foundation]
-rw-r--r--    1 nobody   nobody       1128 déc  5 13:00 deploy.txt
-rwxr-xr-x    1 nobody   nobody   69035365 déc  5 13:00 fnd_linux_install.bin
drwxr-xr-x    2 nobody   nobody       4096 déc  5 13:00 images
-rw-r--r--    1 nobody   nobody      15114 déc  5 13:00 index.html
-rw-r--r--    1 nobody   nobody      23779 déc  5 13:00 license.txt
-rw-r--r--    1 nobody   nobody      75739 déc  5 13:00 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 déc  5 13:00 whatsnew.html
[ls -l docs]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

En los dos directorios generados, el archivo .bin es el archivo de instalación. Además, abre con un navegador el archivo index.html de cada uno de los directorios. Estos archivos indican los pasos a seguir para instalar ambos productos. Comencemos por instalar JBuilder Foundation:

[cd foundation]
[./fnd_linux_install.bin]

Aparece la primera pantalla de la instalación. Le seguirán muchas otras:

Image

Confirme. A continuación, aparece una pantalla con explicaciones:

Image

Ejecute [suivant].

Image

Acepte el contrato de licencia y ejecute [suivant].

Image

Acepta la ubicación propuesta para JBuilder (anótala, la necesitarás más adelante) y ejecuta [suivant]. La instalación se realiza rápidamente.

Image

Ya estamos listos para una primera prueba. En KDE, abre el administrador de archivos para ir al directorio de los ejecutables de JBuilder: /opt/jbuilder4/bin (si instalaste JBuilder en /opt/jbuilder4):

Image

Haz clic en el ícono jbuilder que aparece arriba. Como es la primera vez que usas JBuilder, tendrás que ingresar tu clave de activación:

Image

Llena los campos Nom y Société. Seleccione [Ajouter] para ingresar su clave de activación. Le recordamos que esta clave se le debe haber enviado por correo electrónico y que, si la ha perdido, puede recuperarla en la URL donde descargó JBuilder 4 (véase el inicio de la instalación). Una vez que se acepte su clave de activación, se le recordarán los términos de la licencia:

Image

Al presionar OK, regresará a la ventana de ingreso de información que ya ha visto:

Image

Teclee OK para finalizar esta etapa, que solo se ejecuta la primera vez. A continuación, aparecerá el entorno de desarrollo de JBuilder:

Image

Sal de JBuilder para instalar ahora la documentación. Esta instalará una serie de archivos que se utilizarán en la ayuda de JBuilder, la cual, por el momento, está incompleta. Regresa al directorio donde descomprimiste los archivos tar.gz de JBuilder. El programa de instalación se encuentra en el directorio docs. Navega hasta ese directorio:

[cd docs]
[ls -l]
-rw-r--r--    1 nobody   nobody       1128 oct 10  2000 deploy.txt
-rwxr-xr-x    1 nobody   nobody   40497874 oct 10  2000 doc_install.bin
drwxr-xr-x    2 nobody   nobody       4096 oct 10  2000 images
-rw-r--r--    1 nobody   nobody       9210 oct 10  2000 index.html
-rw-r--r--    1 nobody   nobody      23779 oct 10  2000 license.txt
-rw-r--r--    1 nobody   nobody      75739 oct 10  2000 release_notes.html
-rw-r--r--    1 nobody   nobody      31902 oct 10  2000 whatsnew.html

El archivo de instalación es doc_install.bin, pero no se puede ejecutar de inmediato. Si lo haces, la instalación fallará sin que se entienda por qué. Lee el archivo index.html con un navegador para obtener una descripción detallada del proceso de instalación. El instalador necesita una máquina virtual Java, concretamente un programa llamado java, y este debe estar en el directorio PATH de tu equipo. Recordamos que PATH es una variable de Unix cuyo valor, en el formato rep1:rep2:...:repn, indica los directorios repi que deben explorarse en la búsqueda de un ejecutable. En este caso, el instalador solicita la ejecución de un programa java. Es posible que tengas varias versiones de este programa, dependiendo del número de máquinas virtuales de Java que hayas instalado en distintos lugares. Lógicamente, utilizaremos la que viene con JBuilder 4 y que se encuentra en /opt/jbuilder4/jdk1.3/bin. Para establecer este directorio en la variable PATH:

[echo $PATH]
/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin
[export PATH=/opt/jbuilder4/jdk1.3/bin/:$PATH]
[echo $PATH]
/opt/jbuilder4/jdk1.3/bin/:/usr/local/sbin:/usr/sbin:/sbin:/usr/local/sbin:/usr/local/bin:/sbin:/bin:/usr/sbin:/usr/bin:/usr/X11R6/bin:/root/bin

Ahora podemos iniciar la instalación de la documentación:

[./doc_install.bin]
Preparing to install...

Se llevará a cabo una instalación gráfica:

Image

Es muy similar a la de JBuilder Foundation. Por lo tanto, no la detallaremos. Hay una pantalla que no debe pasarse por alto:

Image

Normalmente, el instalador debe detectar por sí solo dónde instalaste JBuilder Foundation. Por lo tanto, no modifiques lo que se te propone, a menos, claro está, que sea incorrecto.

Una vez instalada la documentación, estamos listos para una nueva prueba de JBuilder. Inicie la aplicación como se mostró anteriormente. Una vez que JBuilder esté abierto, seleccione la opción Ayuda/Tema de ayuda. En el panel de la izquierda, haga clic en el enlace Tutoriels:

Image

JBuilder incluye un conjunto de tutoriales que te permitirán iniciarte en la programación en Java. A continuación, hemos seguido el tutorial «Creación de una aplicación» mencionado anteriormente.

Image

En JBuilder, seleccione Archivo/Nuevo proyecto. Un asistente le mostrará tres pantallas:

Image

Vamos a crear una ventana sencilla con el título «Hola a todos». Llamaremos a este proyecto coucou. El ejemplo se ejecutó mediante root. JBuilder propone entonces agrupar todos los proyectos en un directorio jbproject dentro del directorio de conexión de root. El proyecto coucou se colocará en el directorio coucou (campo «Nombre del directorio del proyecto») de jbproject. Crea [suivant].

Image

Esta segunda pantalla es un resumen de las diferentes rutas de su proyecto. No hay nada que modificar. Seleccione [suivant].

Image

La tercera pantalla te pide que personalices tu proyecto. Completa los datos y ejecuta [Terminer].

Ahora ejecute Fichier/Nouveau:

Image

Seleccione Application y ejecute OK. Un nuevo asistente le mostrará dos pantallas:

Image

El campo paquet toma el nombre del proyecto. El campo «clase» solicita el valor nom, que se asignará a la clase principal del proyecto. Tome el nombre anterior y escriba [suivant]:

Image

Nuestra aplicación cuenta con una segunda clase Java para la ventana de la aplicación. Asigne un nombre a esta clase. El campo Titre es el título que desea darle a esta ventana. El cuadro options le ofrece opciones para su ventana. Seleccione todas y establezca [Terminer]. A continuación, regresará al entorno JBuilder, que ahora cuenta con la información que ha proporcionado para su proyecto:

Image

En la ventana de la parte superior izquierda (1), tienes la lista de archivos que componen tu proyecto. Entre ellos se encuentran las dos clases .java a las que acabamos de asignar un nombre. En la ventana de la derecha (2) tienes el código Java de la clase coucouCadre. En la ventana de la izquierda/parte inferior, se muestra la estructura (clases, métodos, atributos) de su proyecto. Está listo para ejecutarse. Presione el botón 4 de arriba, seleccione Ejecutar/Ejecutar el proyecto o seleccione F9. Debería aparecer la siguiente ventana:

Image

Al hacer clic en la opción Aide, deberías ver la información que ingresaste en los asistentes de creación. No seguiremos adelante. Ahora es momento de sumergirte en los tutoriales.

Antes de terminar, veamos simplemente que puedes usar no solo JBuilder y su interfaz gráfica, sino también el JDK que trajo consigo y que se ubicó en /opt/jbuilder4/jdk1.3. Compila el siguiente archivo essai1.java:

import java.io.*;

public class essai1{
    public static void main(String args[]){
        System.out.println("coucou");
        System.exit(0);
    }
}

Compilémoslo y ejecutémoslo con el JDK de JBuilder:

[ls -l *.java]
-rw-r--r--    1 root     root          135 mai  9 21:57 essai1.java
[/opt/jbuilder4/jdk1.3/bin/javac essai1.java]
[/opt/jbuilder4/jdk1.3/bin/java essai1]
coucou