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:

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:
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:

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á:
¿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:
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:
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:

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

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í:

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

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:

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:
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.
- Inicia JBuilder y selecciona la opción Archivo/Nuevo proyecto. A continuación, aparecerá la primera página de un asistente:

- 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]
- Una pantalla confirma las opciones seleccionadas en el paso anterior

Seleccione [suivant]
- Aparece una nueva pantalla que le pide que defina su proyecto:

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

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

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]
- Aparecerá la siguiente pantalla:

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]
- 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

- 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:

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:

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:

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:

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:
- la función main define el aspecto de la ventana (setLookAndFeel) y crea una instancia de la clase début.
- 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.
- 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.
- 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:

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

El archivo début2.java se reduce a su forma más simple:
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

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

Seleccione début2 y cambie [OK].

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
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 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");
}
- El desarrollador comienza diciendo que va a manejar los eventos en la ventana (enableEvents), y luego ejecuta el método jbInit.
- Se obtiene (getContentPane) el contenedor (JPanel) de la ventana (JFrame)
- Se establece el administrador de formato (setLayout)
- Se establece el tamaño de la ventana (setSize)
- 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:

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.

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

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:

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:

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:

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:

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

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:

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.

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:

y la siguiente estructura:

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

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.

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:

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:
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:

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):


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:
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ú.

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:

Analicemos con más detalle las páginas Sommaire y Index.
5.2.4.1. Ayuda: Índice

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:

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:

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:
![]()
La ayuda mostrará las entradas del índice que comienzan con el texto escrito:

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:

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:

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:

5.2.5.2. componente JComboBox


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.

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
- luego, en el código de jbInit, la lista se asocia al contenedor
Para agregar valores a la lista JList1 anterior, basta con agregarlos a su vector de valores valeurs:
y así se obtiene la siguiente ventana:

¿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:

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:

Se puede conocer el modo de selección actual con getSelectionMode:
![]()
El elemento o los elementos seleccionados se pueden obtener mediante los siguientes métodos:

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:

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

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:

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:

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:

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:

5.2.5.5. componente JScrollBar
Creemos la siguiente aplicación:

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:

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:

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:

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

Este es el resultado, por ejemplo, de RaisedBevel:
![]()
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.

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:

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:

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:

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:

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:

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:
- MousePressed al presionar el botón
- MouseReleased al soltarlo
- 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:

Aquí vemos los tres eventos:
- MousePressed al presionar inicialmente el botón
- MouseDragged al mover el ratón con el botón presionado
- 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?

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:


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.

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

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

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.

Luego, al lado:

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:

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:

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

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):

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:

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

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:

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:

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. Cuadros de diálogo
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:

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:
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:

Visualización de la consola:
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:

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:

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

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:

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:
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:

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:

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:

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

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:

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

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:
¿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:

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:

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
, veremos que JBuilder nos ofrece ayuda:

El paquete com.lamatek se ha encontrado correctamente.
- Ahora, si pasamos al siguiente programa:
Al buscar «F1» con la palabra clave «JFontChooser», se obtiene ayuda sobre esta clase:

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:

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:

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:

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:
![]()
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:
Antes que nada, el usuario debe utilizar la opción de menú Initialiser, que crea un objeto impots con el constructor
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:

- 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:
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:
- la clase application ahora deriva de la clase JApplet
- 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.

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 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:
- eliminar la instrucción que establece el título de la ventana JFrame. Un applet JApplet no tiene barra de título
- 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:

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:

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:

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:

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:
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:

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:

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>

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):

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:

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">
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:
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:
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:

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

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:
[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:
Aparece la primera pantalla de la instalación. Le seguirán muchas otras:

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

Ejecute [suivant].

Acepte el contrato de licencia y ejecute [suivant].

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.

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):

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:

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:

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

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

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:
Se llevará a cabo una instalación gráfica:

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

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:

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.

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

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].

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

La tercera pantalla te pide que personalices tu proyecto. Completa los datos y ejecuta [Terminer].
Ahora ejecute Fichier/Nouveau:

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

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]:

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:

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:

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:






