## La Anatomía de un Programa Basado en Swing

Esta sección mustra un programa Swing, llamado Converter, que tiene un UI gráfico. Puedes ver cómo está implementado este programa mirando el código fuente que puedes encontrar en los ficheros Converter.java y ConversionPanel.java. Sin embargo, no habla sobre líneas individuales de código. Se concentra en cómo el programa Converter usa las características GUI proporcionadas por la plataforma Java. Si te pierdes cuando lees el código fuente de Converter, puedes refrescar tu memoria en la página Una Ruta Rápida por el Código de una Aplicación Swing.

Converter es una aplicación que convierte medidas de distancias entre unidades métricas y américanas. Para ejecutarlo, debes compilar los siguientes ficheros fuente: Converter.java, ConversionPanel.java, ConverterRangeModel.java, FollowerRangeModel.java, DecimalField.java, FormattedDocument.java, y Unit.java. Una vez compilado, puedes ejecutarlo llamando al intérprete con la clase Converter. Si necesitas ayuda para compilar y ejecutar Converter, puedes ver Compilar y Ejecutar un Programa Swing.

Aquí tenemos un gráfico comentado del GUI de Converter:

"JFrame", "JPanel (ConversionPanel)" (x2 apuntado a los paneles que dicen "Metric System" and "U.S. System"), "JTextField (DecimalField)" (x2), JSlider (x2), JComboBox (x2)]

Esta sección describe las siguientes caracterísitcas de Converter:

- Componentes Swing
- El Árbol de Contenidos
- Control de Distribución y Bordes
- Modelos Separados
- Aspecto y Comportamiento Conectable
- Manejo de Eventos

#### Componentes Swing

> Cómo se ve en la figura anterior, Converter tiene los siguientes componentes visibles:
> - 1 JFrame
> - 2 JPanel personalizados
> - 2 JTextField personalizados
> - 2 JSliders
> - 2 JComboBoxes

> El JFrame es el contenedor de alto nivel, sólo proporciona la ventana de la aplicación. Todos los otros componentes de la aplicación están contenidos en JFrame.

> Excepto el contenedor de alto nivel, todos los componentes visibles de Converter descienden de JComponent. La clase JComponent proporciona muchas características, como soporte para bordes y accesibilidad. Los dos JPanel personalizados usan bordes para soportar títulos (por ejemplo, "Metric System") y para dibujar recuadros a su alrededor.

#### El Árbol de Contenidos

> La siguiente figura muesta el árbol de contenidos del JFrame:

>                             JFrame
>                               |
>                              ...
>                               |
>                            JPanel (custom content pane)
>                               |
>                  +---------------------------------+
>                  |                                 |
>               JPanel                            JPanel
>          (ConversionPanel)                 (ConversionPanel)
>                  |                                 | (copy left half here)
>              +---------+
>              |         |
>           JPanel  JComboBox
>          (custom)
>              |
>          +----------+
>          |          |
>     JTextField   JSlider
>     (DecimalField)

> Este diagrama muestra tres componentes no etiquetados en el figura anterior porque no dibujan nada observable en la pantalla.:
> - 1 JPanel que sirve para el panel de contenidos
> - 2 JPanel personalizados que contienen un campo de texto y un deslizador

> Estos tres componentes existen para afectar a la distribución. Hacen esto simplificando la distribución o añadiendo bordes "vacíos" que añaden espacio para la distribución. El agrupamiento de componentes -- tanto en contenedores visibles como en invisibles -- tambien proporciona ayuda para las tecnologías asistivas. Por ejemplo, agrupar un campo de texto y un deslizador en su propio contenedor le ofrece a las tecnologías asisitivas la información de que el campo de texto y el deslizador están estrechamente relacionados.

> Bajo el panel de contenidos hay dos ConversionPanel. Uno de ellos contiene los componentes relacionados con las ditancias métricas, y el otro hace lo mismo con las distancias americanas.

> Cada ConversionPanel contiene 3 componentes visibles: un campo de texto, un deslizador y un combo box. El campo de texto y el deslizador están agrupados en un JPanel, principalmente para simplificar la distribución.

#### Control de Distribución y Bordes

> La siguiente figura muesta una versión coloreada de Converter. En esta versión, cada contenedor tiene un color de fondo diferente, para que puedes ver fácilmente las partes de los contenedores que no están cubiertas por otros componentes. Observa que todos los contenedores son opacos; de otro modo, el color del fondo podría no ser pintado automáticamente.

> Converter create cinco objetos controladores de distribución -- un ejemplar de GridLayout, y cuatro de BoxLayout.

> El primer JPanel (el panel de contenidos personalizado) usa GridLayout para hacer que los ConversionPanels tengan exactamente el mismo tamaño. El código configura el GridLayout para que ponga los ConversionPanels en una sóla columna (dos filas), con cinco pixels entre ellos. El JPanel se inicializa para tener un borde vacío que añade cinco pixels entre el panel y los lados del frame.

> Cada ConversionPanel tiene un borde compuesto. El exterior es un borde con título y el interior es un borde vacío. El borde titulado dibuja una recuadro específico del aspecto y comportamiento alrededor del ConversionPanel y sitúa dentro el título del panel. El borde vacío pone algún espacio más entre el ConversionPanel y sus contenidos.

> Cada ConversionPanel usa un controlador BoxLayout para situar sus contenidos, que son un JPanel y un JComboBox, en un fila. Seleccionando el alineamineto Y tanto del panel como del combo box, el programa alinea la parte superior del panel con la perte superior del combo box.

> El JPanel que agrupa al campo de texto y al deslizador está implementado con una subclase sin nombre de JPanel. Esta subclase sobreescribe los métodos getMinimumSize, getPreferredSize, y getMaximumSize para que devuelvan el mismo valor: 150 pixels de ancho y la altura preferida. Así es como se asegura de que los dos grupos de texto-deslizador tienen la misma anchura, incluso aunque estén controlados por diferentes controladores de distribución. Necesitamos crear una subclase de JPanel, en vez de llamar a los métodos setXxxxSize, porque la altura preferida de los componentes se determina en tiempo de ejecución, por el controlador de distribución.

> El JPanel que agrupa el campo de texto y el deslizador usa un controlador BoxLayout de arriba-a-abajo para que el campo de texto se situe encima del deslizador. El JPanel también tiene un borde vacío que añade un poco de espacio a su derecha entre él y el combo box.

#### Modelos Separados

> Este programa usa tres modelos personalizados. El primero es un modelo de datos para el campo de texto. Los modelos de datos de texto son conocidos como modelos de documento. El modelo de documento analiza el valor que el usuario introduce en el campo de texto. También formatea el número para que parezca bonito. Hemos tomado prestado este modelo de documento, sin cambiarlo, del ejemplo presentado en Crear y Validar y un Campo de Texto.

> Los otros dos modelos personalizados son modelos de datos de deslizador. Esto asegura que el dato mostrado por la aplicación esté en un sólo lugar -- en el modelo del deslizador superior. El modelo del deslizador superior es un ejemplar de una clase personalizada llamada ConverterRangeModel. El deslizador inferior usa una segunda clase personalizada, FollowerRangeModel, que reenvía todas las peticiones para obtener un conjunto de datos al modelo del deslizados superior.

> Todos los modelos de datos de deslizador deben implementar el interface BoundedRangeModel. Aprenderemos esto en la sección del API de Cómo usar Sliders. La documentación del BoundedRangeModel que tiene un clase de implementación llamada DefaultBoundedRangeModel. La documentación del API de DefaultBoundedRangeModel muestra que es una implementación de código general de BoundedRangeModel.

> No usamos DefaultBoundedRangeModel porque almacena los datos como enteros, y necesitamos almacenar datos en coma flotante. Así, implementamos ConverterRangeModel como una subclase de Object, comparálo con el código fuente de DefaultBoundedRangeModel (distribuido con las versiones JFC 1.1y JDK 1.2), para asegurarnos que implementamos el modelo correctamente. Implementamos FollowerRangeModel como una subclase de ConverterRangeModel.

#### Aspecto y Comportamiento Conectable

> El programa Converter se configura a sí mismo para usar el Aspecto y Comportamiento Java. Cambiando el valor de su variable LOOKANDFEEL, podemos hacer que use un Aspecto y Comportamiento diferente. Tres de sus encarnaciones están dibujadas en ¿Qué son el JFC y Swing?.

#### Manejo de Eventos

> El programa Converter crea varios manejadores de eventos:
> Oyentes de Action
>   Cada combo box tiene un oyente de action. Siempre que el usuario selecciona una nueva unidad de medida, el oyente de action notifica el modelo de deslizador relevante y resetea los valores máximos de los dos deslizadores.

>   Cada campo de texto tiene un oyente de action que es notificado cuando el usuario pulsa la tecla Return para indicar que el tecleado ha terminado. Este oyente de action actualiza el correspondiente modelo de deslizador para reflejar el valor del campo de texto.

> Oyente de Change
>   Cada modelo de deslizador tiene un oyente de change personalizado. Siempre que el valor de un deslizador cambia, este oyente actualiza el correspondiente campo de texto. No hemos tenido que registrar los deslizadores como oyentes de dus propios modelos, ya que lo hace Swing automáticamente. En otras palabras, siempre que el programa selecciona un valor en un modelo de deslizador, éste se actualiza automáticamente para reflejar el nuevo estado del modelo.

>   El modelo para el deslizador inferior añade un oyente de cambio al modelo del deslizador superior, Este oyente dispara un evento de cambio al oyente de cambio del modelo del deslizador inferior. El efecto es que cuando cambia el valor del deslizador superior, se actualizan los valores del deslizador y del campo de texto inferior. No es necesario notificar al deslizador superior los cambios en el deslizador inferior, ya que el modelo del deslizador inferior reenvia las peticiones de selección de datos al modelo del deslizador superior.

> Oyentes de Window
>   Un oyente de window en el frame hace que se salga de la aplicación cuando se cierre la ventana.
> Casi todos los oyentes del programa Converter están implementados en clases internas anónimas --clases sin nombre definidas dentro de otras clases. Aunque las clases internas podrían parecer difíciles de leer, al principio, realmente hacen el código mucho más fácil de comprender, una vez que las has utilizado. Manteniendo una implementación de un menejador de eventos cerca de donde se registra el manejador de eventos, las clases internas te ayudan y ayudan a los que te siguen a encontrar fácilmente la implementación completa del manejador de eventos. Puedes ver Usar Adaptadores y Clases Internas para Manejar Eventos para más información.

Ozito