Manual - Programacion - Java - Tutor Swing
Manual - Programacion - Java - Tutor Swing
Esta lección cuenta una pequeña historia sobre JFC y Swing. Si has
desarrollado programas usando componentes SWT, probablemente
estarás interesado en la descripción de las diferencias entre los
componentes ATW y los componentes Swing.
La versión que deberías usar depende de si necesitas usar JDK 1.1 o JDK
1.2. Es más sencillo usar JDK 1.2, ya que no necesitas añadir librerías
para poder usar el API Swing; el JFC construido dentro del JDK 1.2. Sin
embargo, si necesitas usar el JDK 1.1, añadir el API Swing (usando JFC
1.1) no es díficil. Las instrucciones para hacer ambas cosas están en
Compilar y Ejecutar Programas Swing.
.
Swing
Ejecutar el Programa
Puedes desacargar la última versión del JFC 1.1 en la Home Page del
JFC. Esta sección describe la versión Swing 1.1 del JFC 1.1.
2. Anota dónde está instalada tu versión del JDK. Necesitas esto para
poder encontrar las versiones apropiadas de las clases del JDK y el
intérprete. Podrías querer crear una variable de entorno llamada
JAVA_HOME que contenga el path del directorio superior de la
versión del JDK.
Las clases del JDK están en el directorio lib del JDK, en un fichero
llamado classes.zip. No descomprimas este fichero!. El intérprete
Java está en el directorio bin del JDK.
3. Compila la aplicación especificando un classpath que incluya el
fichero swing.jar, el fichero classes.zip, y el directorio que
contenga las clases del programa (normalmente "."). Asegurate de
que el fichero classes.zip y el compilador utilizado son
exactamente de la misma versión del JDK!.
El siguiente ejemplo muestra cómo compilar SwingApplication en un
sistema UNIX. Asume que has configurado las variables de entorno
JAVA_HOME y SWING_HOME.
$JAVA_HOME/bin/javac -classpath .:$SWING_HOME/swing.jar:
$JAVA_HOME/lib/classes.zip SwingApplication.java
Ejecutar el Programa
¿Puedes ver una caja debajo de este párrafo que contiene el texto: "You are
successfully running a Swing applet"? Si es así, tu navegador está configurado
correctamente.
Nota: Como el applet anterior utiliza Java Plug-in 1.1.1, es una versión
Swing 1.0.3 del applet. Para ejecutar la versión Swing 1.1 Beta 3 del
applet, podemos utilizar el AppletViewer para ver
HelloSwingApplet.html, especificando swing.jar en el path de clases
del AppletViewer.
Puedes encontrar el código fuente del applet en
HelloSwingApplet.java, y el código HTML para incluir el applet viendo
el código de ésta misma página. La mala noticia es que el código HTML
para incluir el applet es un poco enrevesado. La buena noticia es que se
puede generar el código HTML para una sencilla etiqueta <APPLET>
automáticamente. Puedes ver la documentación del Java Plug-in para
obtener detalles sobre cómo descargar un conversor HTML gratis.
Aquí puedes ver un applet más complejo, con múltiples ficheros de
clases y un fichero de imagen. El código del applet está en
AppletDemo.java. También utiliza el fichero ../images/middle.gif.
El resto de esta página ofrece instrucciones paso a paso para ejecutar los
applets anteriores.
Paso a Paso: Ejecutar un Applet Basado en Swing
Cada vez que el usuario pulsa el botón, la etiqueta se actualiza. Puedes encontrar
el programa completo en SwingApplication.java.
Para más información sobre los contenedores de alto nivel puedes ver
Los Componentes Swing y el Árbol de Herencia de Contenedores
Para más información sobre los componentes Swing como los botones y
las etiquetas, puedes ver Usar Componentes Swing
Manejar Eventos
Control de la Distribución
Manejo de Eventos
Dibujado
Threads y Swing
● un botón (JButton)
Control de Distribución
Las siguientes figuras muestran los GUIs de cinco programas, cada uno de ellos
muestra cinco botones. Los botones son idénticos, y el código de los programas es
casi idéntico. ¿Entonces por qué parecen tan diferentes? Porque usan diferentes
controladores de distribución para controlar el tamaño y posición de los botones.
Manejo de Eventos
Cada vez que el usuario teclea un caracter o pulsa un botón del ratón, ocurre un
evento. Cualquier puede ser notificado del evento. Todo lo que tiene que hacer es
implementar el interface apropiado y ser registrado como un oyente de evento del
evento fuente apropiado. Los componentes Swing puede generar muchas clases de
evento. Aquí hay unos pocos ejemplos:
Acción que resulta en el evento Tipo de oyente
El usuario pulsa un botón, presiona Return
mientras teclea en un campo de texto, o elige un ActionListener
ítem de menú.
El usuario elige un frame (ventana principal). WindowListener
El usuario pulsa un botón del ratón mientras el
MouseListener
cursor está sobre un componente.
El usuario mueve el cursor sobre un componente. MouseMotionListener
El componente se hace visible. ComponentListener
El componente obtiene obtiene el foco del teclado. FocusListener
Cambia la tabla o la selección de una lista. ListSelectionListener
Cada evento está representado por un objeto que ofrece información sobre el evento
e identifica la fuente. Las fuentes de los eventos normalmente son componentes, pero
otros tipos de objetos también pueden ser fuente de eventos. Como muestra la
siguiente figura, cada fuente de evento puede tener varios oyentes registrados.
Inversamente, un sólo oyente puede registrarse con varias fuentes de eventos.
someComponent.addActionListener(instanceOfMyClass);
3. La implementación de los métodos del interface oyente. Por ejemplo:
ActionEvent
button ----------------------------> action listener
Dibujo
Podrías no necesitar la información de esta sección, en absoluto. Sin embargo, si
tus componentes parece que no se dibujan correctamente, entender los conceptos
de esta sección podría ayudarte a ver qué hay erróneo. De igual modo, necesitarás
entender esta sección si creas código de dibujo personalizado para un componente.
Un Ejemplo de Dibujo
|
JPanel
|
+----------------+
| |
JButton JLabel
Aquí está lo que sucede cuando se dibuja el GUI de SwingApplication:
1. El contenedor de alto nivel, JFrame, se dibuja as sí mismo.
2. El panel de contenido primero dibuja su fondo, que es un rectángulo
sólido de color gris. Luego le dice al JPanel que se dibuje el mismo.
El rectángulo del panel de contenido realmente no aparece en el
GUI finalizado porque está oscurecido por el JPanel.
Nota: Es importante que el panel de contenido sea opaco. De otro
modo, resultará en dibujados confusos. Cómo el JPanel es opaco,
podemos hacer que sea el panel de contenido (sustituyendo
setContentPane por el código existente getContentPane().add).
Esto simplifica considerablemente el árbol de contenidos y el
dibujado, eliminado un contenedor innecesario.
Threads y Swing
Esta página explica como usar el API Swing de forma segura con threads. Si
nuestro programa es un applet, lo más seguro es construir su GUI en el método
init. Si nuestro programa es una aplicación con el siguiente patrón común
estaremos seguros:
//Thread-safe example
public class MyApplication {
public static void main(String[] args) {
JFrame f = new JFrame(...);
...//Add components to the frame here...
f.pack();
f.setVisible(true);
//Don't do any more GUI work here.
}
...
//All manipulation of the GUI -- setText, getText, etc. --
//is performed in event handlers such as actionPerformed().
...
}
Sin embargo, si nuestro programa crea threads que realizan tareas que afectan al
GUI, o manipulan un GUI ya visible en respuesta a algún evento del AWT, ¡sigue
leyendo!
La Regla de los Threads
Los componentes Swing solo pueden ser accedidos por un thread a la vez.
Generalmente, este thread es el que despacha los eventos.
Excepciones a la Regla
Unas pocas operaciones están garantizadas como seguras ante los threads.
Cómo Ejecutar Código en el Thread de Despacho de Eventos
Si necesitamos acceder al UI desde fuera del código del despachador de
eventos o de dibujo, podemos usar los métodos invokeLater o
invokeAndWait.
Cómo crear Threads
Si necesitamos crear un thread -- por ejemplo para manejar un trabajo que
gasta mucho tiempo o paquetes de I/O -- podemos usar uno de los thread
útiles como SwingWorker o Timer.
Excepciones a la Regla
● Iconos
● Actions
● Aspecto y Comportamiento Conectable
● Soporte de Tecnologías Asistivas
● Modelos de Datos y Estados Separados
Iconos
Actions
"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
● 2 JPanel personalizados
● 2 JTextField personalizados
● 2 JSliders
● 2 JComboBoxes
El Árbol de Contenidos
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
Modelos Separados
Manejo de Eventos
La clase JComponent
Usar Componentes
[PENDIENTE: JRootPane]
Root pane Tool bar
Controles Básico
Text Tree
Swing
Aquí podemos ver dos imágenes del mismo programa, FrameDemo.java, ejecutándose en
distintas plataformas. El programa trae un frame que contiene algo interesante que ver.
Solaris Windows
[PENDIENTE]
Abajo podemos ver el código de FrameDemo.java que crea el frame del ejemplo anterior.
frame.pack();
frame.setVisible(true);
}
El código crea un frame con el título A Basic Frame y añade un oyente de window para salir del
programa cuando el usuario cierre el frame.
Las líneas en itálica del código crean la etiqueta que muestra el texto y la imagen del frame.
Este es esencialmente el GUI del programa. Si queremos utilizar este programa como marco de
trabajo para nuestros propios programas, sólo tenemos que reemplazar el código en itálica para
crear los componentes que querramos.
El código en negrita añade la etiqueta al panel de contenido del frame. Puedes ir a Añadir
Componentes a un Frame para más detalles y ejemplos.
Para que un frame aparezca en la pantalla, un programa debe llamar a setSize o a pack, y
luego llamar a setVisible(true) o su equivalente, show. Este programa empaqueta el frame y
utiliza setVisible. Observa que si cualquier parte del GUI ya es visible, deberíamos invocar a
setVisible desde el thread de lanzado de eventos. Puedes ver la página Threads y Swing.
Este código es típico de muchos programas y es el marco de trabajo que hemos utilizado para
crear la mayoría de los ejemplos de esta lección (incluyendo GlassPaneDemo.java y
BorderDemo.java). Algunos ejemplos como TextFieldDemo.java y TableDemo.java,
subclasifican JFrame y ejemplarizan la subclase frame en vez JFrame. En esos programas, el
GUI se crea en el constructor de la subclase. Podríamos hacer esto en nuestros programas si
necesitaramos subclasificar JFrame por alguna razón.
JFrame es una subclase de java.awt.Frame a la que añade soporte para la interposición de
entradas y comportamiento de pintado contra el frame hijo, situando hijos en diferentes "capas"
(layers) y para barras de menús Swing. Generalmente hablando, deberíamos utilizar JFrame en
vez de Frame, por estas razones:
● Para aprovechar las nuevas características proporcionadas por su panel raíz como el panel
transparente y el panel de capas.
● JFrame permite personalizar el comportamiento de la ventana, llamando al método
setDefaultCloseOperation en vez de escribir un oyente de window.
● JFrame soporta el método revalidate.
● Los menús Swing funcionan mejor en un JFrame debido a sus métodos setJMenuBar.
● Deberíamos utilizar JFrame en un applet si éste utiliza componentes Swing. También,
recomendamos la utilización de JFrame en una aplicación que utilice componentes Swing,
aunque no es necesario.
public TableDemo() {
super("TableDemo");
. . .
● Utilizar JFrame.getContentPane para obtener el panel de contenido del frame.
Añadir componentes al objeto devuelto.LayeredPaneDemo.java utiliza esta
técnica mostrada aquí:
EL API JFrame
Las siguientes tablas listan los métodos y constuctores más utilizados de JFrame.
Existen otros métodos que podríamos llamar y que están definidos en las clases
Frame y Window y que incluyen pack, setSize, show, hide, setVisible, setTitle,
y getTitle.
La mayor parte de la opración de un frame está manejada por otros objetos. Por
ejemplo, el interior de un frame está manejado por su panel raíz, y el panel de
contenido contiene el GUI del frame.
El API para utilizar Frames se divide en dos categorías:
● Crear y Configurar un Frame
● DISPOSE_ON_CLOSE
Esta tabla lista ejemplos que utilizan JFrame y dónde poder encontrarlos.
Ejemplo Dónde se describe Notas
FrameDemo.java Un frame básico con un
Esta página.
componente.
TextFieldDemo.java Cómo usar TextFields Una subclase de JFrame.
Una subclase de JFrame que
TableDemo.java Cómo usar Tablas configura el panel de contenido del
frame.
IconDemoApplet.java Como usar Iconos Añade muchos componentes al
panel de contenido por defecto.
LayeredPaneDemo.java Cómo usar LayeredPane Ilustra el uso de panel de capas
del frame.
GlassPaneDemo.java El panel Transparente Ilustra el uso del panel
transparente.
MenuDemo.java Muestra como poner un
Cóm usar Menús
JMenuBar en un JFrame.
Swing
El código para diálogos simples puede ser mínimo. Por ejemplo, aquí tenemos un
diálogo informativo:
● Características de JOptionPane
● El ejemplo DialogDemo
● Personalizar el texto del botón en un diálogo estándard
● Obtener entrada del usuario desde un diálogo
● Detener la despedida automática de un diálogo
● El API Dialog
● Ejemplos que utilizan diálogos
Características de JOptionPane
icono
mensaje
(si existe)
botones
JOptionPane.showMessageDialog(frame,
"Eggs aren't supposed to be green.",
"Inane error",
JOptionPane.ERROR_MESSAGE);
Normalmente, el área del mensaje de un panel de opciones tiene una sóla
línea de texto, como "Eggs aren't supposed to be green." Podemos dividir el
mensaje en varias líneas poniendo caracteres de nueva línea (\n) dentro del
string del mensaje. Por ejemplo:
Intenta esto:
1. Compila y ejecuta la aplicación, El fichero fuente es DialogDemo.java.
2. Pulsa el botón "Show it!".
Aparecerá un diálogo modal. Hasta que lo cierres, la aplicación no
responderá, aunque se redibujará a sí misma si es necesario. Puedes
salir del diálogo pulsando un botón o explícitamente utilizando el icono
de cerrado de la ventana.
3. Minimiza la ventana DialogDemo mientras se muestra el diálogo.
El diálogo desaparecerá de la pantalla hasta que maximices la ventana
de DialogDemo.
4. En el panel "More Dialogs", pulsa el botón de rádio iferior y luego el
botón "Show it!". Aparecerá un diálogo no modal. Observa que la
ventana de DialogDemo permanece totalmente funcional mientras está
activo el diálogo no modal.
if (dialog.isVisible()
&& (e.getSource() == optionPane)
&& (prop.equals(JOptionPane.VALUE_PROPERTY) ||
prop.equals(JOptionPane.INPUT_VALUE_PROPERTY))) {
//If you were going to check something
//before closing the window, you'd do
//it here.
dialog.setVisible(false);
}
}
});
dialog.pack();
dialog.show();
El API Dialog
public ButtonDemo() {
super();
...
create the three buttons
...
//Add Components to this container, using the default FlowLayout.
add(b1);
add(b2);
add(b3);
}
Este código no selecciona explícitamente el controlador de distribución del panel,
por eso utiliza el controlador por defecto. Este controlador de distribución,
FlowLayout, sitúa los componentes en una fila con sus tamaños preferidos. Si
queremos utilizar otro controlador de distribución, podemos especicar el
controlador cuando creamos el objeto JPanel o utilizar el método setLayout
posteriormente. El AWT proporciona una colección de útiles controladores de
distribución, y Swing añade otro controlador de distribución de propósito general,
BoxLayout.
El fragmento de código anterior utiliza un método add heredado de
java.awt.Container que requiere un sólo argumento: el componente a añadir.
Como otras subclases de Container, JPanel hereda otros métodos add que
permiten especificar restricciones e información sobre posicionamiento cuando se
añade un componente. Se debe elegir el método add para el controlador de
disposición que se está utilizando.
Otros Contenedores
El API JPanel
El API de la propia clase JPanel es mínimo. Los métodos que más se
utilizan de un objeto JPanel son aquellos que hereda de sus superclases
JComponent, Container y Component.
● Crear un JPanel
● Manejar Componentes en un Contenedor
● Seleccionar/Obtener el Controlador de Distribución
Crear un JPanel
Método Propósito
Crea un panel. Cuando está
presente, el parámetro boolean
determina la estrategía de buffer
JPanel() del panel. Un valor true indica
JPanel(boolean) doble buffer. El parámetro
JPanel(LayoutManager) LayoutManager proporciona el
JPanel(LayoutManager, boolean) controlador de distribución para el
nuevo panel. Si no se especifica,
el panel utiliza FlowLayout para
distribuir sus componentes.
Manejar Componentes en un Contenedor
Método Propósito
Añade el componente
especificado al panel. Cuando
existe, el parámetro int es la
posición o índice del
componente dentro del
contenedor. El parámetro
void add(Component)
Object depende del
void add(Component, int)
controlador de distribución y
void add(Component, Object)
normalmente proporciona
void add(Component, Object, int)
información sobre el
void add(String, Component)
posicionamiento y
restricciones de distribución
cuando se añaden
componentes. El parámetro
String proporciona un
nombre para el componente.
Obtiene el número de
int getComponentCount()
componentes en este panel.
Obtiene el componente o
Component getComponent(int)
componentes especificados.
Component getComponentAt(int, int)
Se pueden obtener
Component getComponentAt(Point)
basándose en su índice, o en
Component[] getComponents()
sus posiciones x,y.
void remove(Component)
Elimina el componente o
void remove(int)
componentes especificados.
void removeAll()
Seleccionar/Obtener el Controlador de Distribución
Método Propósito
Selecciona u obtiene el controlador
de distribución para este panel. El
void setLayout(LayoutManager) controlador de distribución es el
LayoutManager getLayout() responsable de posicionar los
componentes dentro del panel de
acuerdo con alguna filosofía.
Y aquí está el código que crea el área de texto, crea el cliente del panel desplazable, y
añade el panel desplazable a la ventana:
Aquí puedes ver una imagen de una aplicación que utiliza un panel desplazable
para ver una foto del padre de Mary cuando era joven:
El panel desplazable de esta aplicación parece totalmente diferente del de la
aplicación anterior. En vez de texto, contiene una gran imagen. El ScrollPane
también tiene dos barras de desplazamiento, un fila y una columna de
cabecera y tres esquinas personalizadas, una de las cuales contiene un botón.
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
ScrollDemo.java. También necesitarás
ScrollablePicture.java, Rule.java, Corner.java y
youngdad.jpeg.
2. Mueve las barras de desplazamiento. Mira que la imagen se
mueve y con ella las reglas vertical y horizontal.
3. Pulsa el botón cm en la esquina superior izquierda. Las
unidades de las cabecera de fila y de columna cambian a
pulgadas (o vuelve a centímetros).
4. Pulsa las flechas de las barras de desplazamiento. También,
pulsa sobre el camino de las barras de desplazamiento arriba o
debajo de la barra vertical, o a la izquierda o derecha de la
barra horizontal.
5. Aumenta el tamaño de la ventana. Observa que las barras
desaparecen cuando no son necesarias y como resultado las
esquina añadidas también desparecen. Disminuye la ventana y
las barras de desplazamiento y las esquinas reaparecerán.
Vigilante Descripción
Valor por defecto. Las barras
de desplazamiento aparecen
VERTICAL_SCROLLBAR_AS_NEEDED cuando el JViewPort es más
HORIZONTAL_SCROLLBAR_AS_NEEDED pequeño que el cliente y
desaparecen cuando es más
grande.
VERTICAL_SCROLLBAR_ALWAYS
Siempre muestra las barras.
HORIZONTAL_SCROLLBAR_ALWAYS
Nunca muestra las barras de
desplazamiento. Se utiliza
esta opción si no queremos
darle al usuario el control
VERTICAL_SCROLLBAR_NEVER
sobre la parte del cliente a
HORIZONTAL_SCROLLBAR_NEVER
visualizar. Quizás tengamos
alguna aplicación que requiera
que el desplazamiento ocurra
programáticamente.
● getScrollableUnitIncrement
● getPreferredViewportSize
● getScrollableTracksViewportHeight
● getScrollableTracksViewportWidth
El API de ScrollPane
● Decorar el ScrollPane
● Implementar el Interface Scrollable
Configurar el ScrollPane
Método Propósito
Crea un ScrollPanel El parámetro
JScrollPane() Component, cuando existe, selecciona el
JScrollPane(Component) cliente. Los dos parámetros int, cuando
JScrollPane(int, int) existen, seleccionan los vigilantes de
JScrollPane(Component, int, int) seguridad de las barras de desplazamiento
vertical y horizontal (respectivamente):
void
Selecciona el cliente del ScrollPane.
setViewportView(Component)
Selecciona u obtiene el vigilante de
desplazamiento vertical.
ScrollPaneConstants define tres valores
void
para especificar estos vigilantes:
setVerticalScrollBarPolicy(int)
VERTICAL_SCROLL_BAR_AS_NEEDED
int getVerticalScrollBarPolicy()
(por defecto),
VERTICAL_SCROLL_BAR_ALWAYS, y
VERTICAL_SCROLL_BAR_NEVER.
Selecciona u obtiene el vigilante de
desplazamiento horizontal.
void ScrollPaneConstants define tres valores
setHorizontalScrollBarPolicy(int) para especificar estos vigilantes:
int HORIZONTAL_SCROLL_BAR_AS_NEEDED
getHorizontalScrollBarPolicy() (por defecto),
HORIZONTAL_SCROLL_BAR_ALWAYS, y
HORIZONTAL_SCROLL_BAR_NEVER.
void setViewportBorder(Border) Selecciona u obtiene el borde alrededor del
Border getViewportBorder() JViewport.
Decorar el ScrollPane
Método Propósito
void setColumnHeaderView(Component) Selecciona la cabecera de fila o
void setRowHeaderView(Component) de columna para el ScrollPane.
Seleciona u obtiene la esquina
especificada. El parámetro int
indica qué columna y debe ser
una de las siguientes
void setCorner(Component, int) constantes definidas en
Component getCorner(int) ScrollPaneConstants:
UPPER_LEFT_CORNER,
UPPER_LEFT_CORNER,
LOWER_LEFT_CORNER, y
LOWER_LEFT_CORNER.
Implementar el Interface Scrollable
Método Propósito
Obtiene el incremento de unidad
o de bloque en pixels. El
parámetro Rectangle son los
límites del área visible
actualmente. El primer
int
parámetro int es
getScrollableUnitIncrement(Rectangle,
SwingConstants.HORIZONTAL
int, int)
o SwingConstants.VERTICAL
void
dependiendo de la barra que
getScrollableBlockIncrement(Rectangle,
haya pulsado el usuario. El
int, int)
segundo parámetro int indica la
dirección del desplazamiento. Un
valor menor que 0 indica arriba o
izquierda. Una valor mayor que 0
indica abajo o derecha.
Obtiene el tamaño preferido del
JViewport. Esto permite al cliente
influenciar en el tamaño del
Dimension
componente en el que va ser
getPreferredScrollableViewportSize()
mostrado. Si este tamaño no es
importante devuelve
getPreferredSize.
Obtiene su el ScrollPane debería
forzar al cliente a tener la misma
boolean anchura o altura que el
getScrollableTracksViewportWidth() JViewport. Devolver true por
boolean alguno de esto métodos
getScrollableTracksViewportHeight() efectivamente desactiva el
desplazamiento horizontal o
vertival (respectivamente).
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
SplitPaneDemo.java. imagenames.properties proporciona los
nombres de las imagenes para poner en el JList.
2. Arrastra la línea que divide la lista y la imagen a la izquierda o a la
derecha. Intenta arrastrar el divisor más allá del límite de la
ventana.
3. Utiliza las flechas del divisor para ocultar alguno de los
componentes.
La clase principal del programa de ejemplo se llama SplitPaneDemo y es una
subclase de JSplitPane. Aquí podemos ver el código del constructor de
SplitPaneDemo que crea y configura el SplitPane:
public SplitPaneDemo() {
// Provide minimum sizes for the two components in the split pane
Dimension minimumSize = new Dimension(100, 50);
listScrollPane.setMinimumSize(minimumSize);
pictureScrollPane.setMinimumSize(minimumSize);
El API de SplitPane
Configurar el SplitPane
Método Propósito
Crea un SplitPane. Cuando
existe, el parámetro int
indica la orientación del
SplitPane,
HORIZONTAL_SPLIT o
JSplitPane() VERTICAL_SPLIT. El
JSplitPane(int) paramétodo booleano
JSplitPane(int, boolean) selecciona si los
JSplitPane(int, Component, Component) componentes se redibujan
JSplitPane(int, boolean, Component, contínuamnete cuando el
Component) usuario arrastra el divisor.
Los parámetros
Component seleccionan
los componentes izquierdo
y derecho o superior e
inferior, respectivamente.
Selecciona u obtiene la
orientación del SplitPane.
void setOrientation(int) Se utilizan
int getOrientation() HORIZONTAL_SPLIT o
VERTICAL_SPLIT
definidas en JSplitPane.
Selecciona u obtiene el
void setDividerSize(int)
tamaño del divisor en
int getDividerSize()
pixels.
Selecciona u obtiene si los
componetes del SplitPane
void setContinuousLayout(boolean)
se redistribuyen y
boolean getContinuousLayout()
redibujan mientras el
usuario arrastra el divisor.
Selecciona u obtiene si el
void setOneTouchExpandable(boolean) SplitPane muestra los
boolean getOneTouchExpandable() botones de control
expandible.
Manejar los Contenidos del SplitPane
Método Propósito
void setTopComponent(Component)
void setBottomComponent(Component)
Selecciona u obtiene el
void setLeftComponent(Component)
componente indicado.
void setLEFTComponent(Component)
Cada método funciona sin
Component getTopComponent()
importarle la orientación
Component getBottomComponent()
del SplitPane.
Component getLeftComponent()
Component getLEFTComponent()
void remove(Component) Elimina el componente
void removeAll() indicado del SplitPane.
Añade el componete al
SplitPane. Podemos añadir
dos componentes a un
SplitPane. El primer
void add(Component) componente se añade al
componente
superior/izquierda; y el
segundo al componente
inferior/derecha.
Posicionar el Divisor
Método Propósito
Selecciona u obtiene la posición
actual del divisor. Cuando se
selecciona la posición, podemos
especificar un porcentaje
(double) o una posición de pixel
(int).
Nota: Las veriones Swing 1.0.3 y
anteriores tenían un bug por el
void setDividerLocation(double)
que setDividerLocation era
void setDividerLocation(int)
ignorado si se le llamaba antes de
int getDividerLocation()
que los componentes fueran
visibles. Para evitar esto, se
seleccioa la anchura (o altura)
preferida del componente de la
izquierda (o superior) al mismo
valor en que queríamos usar
como argumento de
setDividerLocation(int).
void setLastDividerLocation(int) Selecciona u obtiene la posición
int getLastDividerLocation() anterior del divisor.
Obtienen las posiciones mínima y
máxima del divisor. Estas se
int getMaximumDividerLocation() seleccionan implícitamente
int getMinimumDividerLocation() seleccionando los tamaños
mínimos de los dos componetes
del SplitPane.
Intenta esto:
1. Compila y ejecuta la aplicación. El código fuente esta en
TabbedPaneDemo.java.
2. Pon el cursor sobre una pestaña. Después de un corto tiempo, verás
una ayuda (tooltip) asociada con la pestaña. Como conveniencia se
debe añadir el texto de la ayuda (tooltip) cuando se añade el
componente al TabbedPane.
3. Selecciona una pestaña. El TabbedPane muestra el componente
correspondiente a la pestaña.
El API TabbedPane
public ToolBarDemo() {
...
JToolBar toolBar = new JToolBar();
addButtons(toolBar);
...
JPanel contentPane = new JPanel();
contentPane.setLayout(new BorderLayout());
...
contentPane.add(toolBar, BorderLayout.NORTH);
contentPane.add(scrollPane, BorderLayout.CENTER);
...
}
//first button
button = new JButton(new ImageIcon("images/left.gif"));
...
toolBar.add(button);
//second button
button = new JButton(new ImageIcon("images/middle.gif"));
...
toolBar.add(button);
//third button
button = new JButton(new ImageIcon("images/LEFT.gif"));
...
toolBar.add(button);
}
Añadiendo unas pocas líneas de código al ejemplo anterior, podemos demostrar
algunas características más de las barras de herramientas:
● Usar el método setFloatable para hacer que la barra no se pueda mover.
Aquí está una imagen del nuevo GUI, que está implementado por
ToolBarDemo2.java:
toolBar.setFloatable(false);
La mayor diferencia visible es que la barra de herramientas contiene dos
componentes nuevos, que están precedidos por un espacio en blanco -- un
separador . Aquí está el código que añade el separador:
toolBar.addSeparator();
Aquí está el código que añade los nuevos componentes:
Como se ve en la figura, los frames internos utilizan la decoración de ventana del aspecto y
comportamiento Metal. Sin embargo, la ventana que los contiene tiene decoración de aspecto y
comportamiento nativo (en este caso, Motif).
Intenta esto:
1. Compila y ejecuta la aplicación, Los ficheros fuentes son:
InternalFrameDemo.java y MyInternalFrame.java.
2. Crea nuevos frames internos utilizando el ítem Create en el menú Document.
Cada frame interno viene 30 pixels por debajo y a la derecha de la posición del
frame anterior. Esta funcionalidad se implementa en la clase MyInternalFrame,
que es la subclase peronalizada de JInternalFrame.
public MyInternalFrame() {
super("Internal Frame #" + (++openFrameCount),
true, //resizable
true, //closable
true, //maximizable
true);//iconifiable
//...Create the GUI and put it in the window...
//...Then set the window size or call pack...
...
//Set the window's location.
setLocation(xOffset*openFrameCount, yOffset*openFrameCount);
}
El código para utilizar frames internos es similar en muchas formas al código para
utilizar frames normales Swing. Como los frames internos tienen sus paneles raíz,
configurar el GUI para un JInternalFrame es muy similar a configurar el GUI para
un JFrame. JInternalFrame también proporciona otro API, como pack, que lo hace
similar a JFrame.
Como los frames internos no son ventanas, de alguna forma son diferentes de los
frames. Por ejemplo, debemos añadir un frame interno a un contenedor
(normalmente un JDesktopPane). Un frame interno no genera eventos window; en
su lugar, las acciones del usuario que podrían causar que un frame dispara eventos
windows hacen que en un frame interno se disparen eventos "internal frame".
Como los frames internos se han implementado con código independiente de la
plataforma, ofrecen algunas características que los frames no pueden ofrecer. Una de
esas características es que los frames internos ofrecen más control sobre su estado y
capacidades. Programáticamente se puede minimizar o maximizar un frame interno.
También se puede especificar el icono que va en la barra de título del frame interno.
Incluso podemos especificar si el frame tiene soporte de decoración de ventanas,
redimensionado, minimización, cerrado y maximización.
Otra característica es que los frames internos se han diseñado para trabajar con
paneles por capas. El API JInternalFrame contiene métodos como moveToFront
que funcionan sólo si el contenedor de un frame interno es un layeredpane.
Si has construido algún programa utilizando JFrame y los otros componentes Swing,
entonces ya sabes mucho sobre cómo utilizar frames internos. La siguiente lista
sumariza las reglas para la utilización de frames internos.
Se debe seleccionar el tamaño del frame interno.
Si no se selecciona el tamaño del frame interno, tendrá tamaño cero y nunca
será visible. Se puede seleccionar el tamaño utilizando uno de estos métodos:
setSize, pack o setBounds.
Como regla, se debe seleccionar la posición del frame interno.
Si no se selecciona la localización, empezará en 0,0 (la esquina superior
izquierda de su contenedor). Se pueden utilizar los métodos setLocation o
setBounds para especificar la esquina superior izquierda del frame interno en
relación a su contenedor.
Para añadir componentes a un frame interno, se añaden al panel de
contenidos del propio frame interno.
Es exactamente la misma situación que JFrame. Puedes ver Añadir
componentes a un Frame para más detalles.
Los diálogos que son frames internos deberían implementarse utilizando
JOptionPane o JInternalFrame, no JDialog.
Para crear un diálogo sencillo, podemos utilizar los metodos
showInternalXxxDialog de JOptionPane, como se describió en Cómo crear
Diálogos. Observa que los diálogos en frames internos no son modales.
Un frame interno se debe añadir a un contenedor
Si no lo añadimos a un contenedor (normalmente un JDesktopPane), el frame
interno no aparecerá.
Normalmente no se tiene que llamar a show o setVisible para los frames
internos.
Al igual que los botones, los frames internos se muestran automáticamene
cuando se añaden a un contenedor visible o cuando su contenedor
anteriormente invisible se hace visible.
Los frames internos disparan eventos "internal frame", no eventos
"window".
El manejo de eventos "internal frame" es casi idéntico al manejo de eventos
"window". Para más información puedes ver Cómo escribir un oyente "Internal
Frame".
El API de InternalFrame
Junto con el API listado abajo, JInternalFrame hereda un API útil desde
JComponent, Container, y Component. JInternalFrame también proporciona
métodos para obtener y seleccionar objetos adicionales en su panel raíz. Para más
detalles puedes ver Cómo usar RootPane.
● showInternalOptionDialog
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es LayeredPaneDemo.java.
También necesitarás cinco ficheros de imágenes: Bird.gif, Cat.gif, Dog.gif,
Rabbit.gif, y Pig.gif.
2. Cuando arranca, el programa crea cinco frames internos. Para crear otro frame,
selecciona una capa desde el combo box luego pulsa el botón Create a Frame.
3. Mueve los frames alrededor. Observa la relación de los frames en las diferentes
capas y los frames de al misma capa.
4. Observa que se puede arrastrar un frame interno sobre los controles de la parte
superior del programa. Los controles están en el panel de contenido del frame
principal que está en una capa inferior a todas las capas disponibles desde el
menú.
El API LayeredPane
Las siguientes tablas listan los métodos y constructores más utilizados de la clase
JLayeredPane. Otros métodos interesantes están definidos por las clases
JComponent y Component.
Esta tabla muestra ejemplos que utilizan JLayeredPane y dónde poder encontarlos.
Ejemplo Dónde se Describe
Notas
LayeredPaneDemo.java Esta Página. Ilustra las capas y las posiciones
inter-capas de un JLayeredPane.
Cómo usar Frames Utiliza un JDesktopFrame para
InternalFrameDemo.java
Internos manejar frames internos.
Swing
La página Reglas Generales para Usar Componentes Swing explica lo básico sobre
el uso de paneles raíz -- obtener el panel de contenido, seleccionar su controlador
de distribución, y añadirle componentes Swing. Esta página explica más cosas sobe
los paneles raíz, incluyendo los componentes que crean un panel raíz, y cómo
poder utilizarlos.
Un panel raíz se divide en cuatro partes:
El Panel de Cristal
Oculto, por defecto. Si se hace visible, es como si se pusiera una hoja de
cristal sobre las otras partes del panel raiz. Es completamente transparente (a
menos que hagamos que el método paint haga algo) e intercepta los eventos
de entrada para el panel raíz. En la siguiente sección, veremos un ejemplo de
utilización de un panel de cristal.
El panel de capas
Sirve para posicionar sus contenidos, que consisten en el panel de contenido y
la barra de menú opcional. También puede contener otros componentes en un
orden Z especificado. Para más información puedes ver Cómo usar Layered
Panes.
El Panel de Contenido
El contenedor de los componentes visibles del panel raíz, excluyendo la barra
de menú.
La barra de menú opcional
El hogar para los menús del panel de contenido. Si el contenedor tiene una
barra de menús, generalmente se utilizan los métodos setMenuBar o
setJMenuBar del contenedor para poner la barra de menú en el lugar
apropiado.
El Panel de Cristal
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
GlassPaneDemo.java.
2. Pulsa le botón 1.
La apariencia del botón cambia para indicar que ha sido
pulsado.
3. Pulsa el checkbox para que el panel de cristal se vuelva
"visible", y luego pulsa el botón 1, otra vez.
El botón no detecta la pulsación del ratón porque el panel
de cristal la ha interceptado. Cuando el panel de cristal
detecta el evento, suena un pitido y dibuja un círculo rojo
donde se pulsó.
4. Pulsa de nuevo sobre el checkbox para ocultar el panel de
cristal.
Cuando el panel raíz detecta un evento sobre el
checkbox, lo reenvía al checkbox. De otro modo, el
checkbox no podría responder a las puslaciones.
if (containerPoint.y < 0) {
inMenuBar = true;
//...set container and containerPoint accordingly...
testForDrag(eventID);
}
component = SwingUtilities.getDeepestComponentAt(
container,
containerPoint.x,
containerPoint.y);
if (component.equals(liveButton)) {
inButton = true;
testForDrag(eventID);
}
if (repaint) {
toolkit.beep();
glassPane.setPoint(glassPanePoint);
glassPane.repaint();
}
}
Las siguientes tablas listan el API para utilizar paneles raíz, paneles de
cristal y paneles de contenido:
● Usar un Panel Raíz
● El API Menu
Todo programa Swing utiliza un panel raíz. Los ejemplos de esta lista
ilustran algunos de los usos más comunes e interesantes. También
puedes ver:
● Ejemplos que usan Layered Panes
Aquí tienes una imagen de una aplicación que muestra tres botones:
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente está en
ButtonDemo.java.
Puedes ver Empezar con Swing si necesitas ayuda.
2. Pulsa el botón izquierdo.
Deshabalita el botón central (y a sí mismo, ya que no es necesario)
y activa el botón derecho.
3. Pulsa el botón derecho.
Activa los botones central e izquierdo y se desactiva a a sí mismo.
El API Button
Aquí podemos ver una imagen de una aplicación que utiliza cuatro checkboxes para
personalizar una caricatura:
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
CheckBoxDemo.java. También necesitarás los 16 ficheros de
imagenes del directorio example-swing/images que empiezan
con "geek".
2. Pulsa el botón Chin o pulsa Alt-C.
El checkbox Chin se desactiva, y la barbilla desaparecerá de la
imagen. Los otros Checkboxes permanencen seleccionados. Esta
aplicación tiene un oyente de ítem que escucha todos los
checkboxes. Cada vez que el oyente de ítem recibe un evento, la
aplicación carga una nueva imagen y refleja el estado actual de los
checkboxes.
if (source == chinButton) {
//...make a note of it...
} else if (source == glassesButton) {
//...make a note of it...
} else if (source == hairButton) {
//...make a note of it...
} else if (source == teethButton) {
//...make a note of it...
}
if (e.getStateChange() == ItemEvent.DESELECTED)
//...make a note of it...
picture.setIcon(/* new icon */);
...
}
}
El API CheckBox
El selector de color consiste en cualquier cosa que hay dentro del borde llamado
Choose Background Color. Contiene dos partes, un panel con pestañas y un panel
de previsionado. Las tres pestañas delprimero seleccionan un panel selector diferente.
El preview panel mustra el color seleccionado actualmente.
Aquí podemos ver el código del ejemplo que crea un ejemplar de JColorChooser y lo
añade a la ventana:
colorChooser.getSelectionModel().addChangeListener(
new ChangeListener() {
public void stateChanged(ChangeEvent e) {
Color newColor = colorChooser.getColor();
banner.setColor(newColor);
}
}
);
El oyente de Change obtiene el color seleccionado actualmente desde el selector de
color y lo utiliza para seleccionar el color de fondo del banner. Puedes ver Cómo
escribir un oyente de Change para información general sobre los evento de "Change" y
sus oyentes.
Un selector de color básico , como el utilizado en el programa de ejemplo, es
suficiente para muchos programas. Sin embargo, el API ColorChooser permite
personalizar un selector de oclor proporcionando un panel de previsionado de nuestro
propio diseño, añadiéndolo nuestros propios paneles, o eliminando los panles del
selección existentes en el selector de color. Además, la clase ColorChooser
proporciona dos métodos que hacen muy sencillo el uso de un selector de color dentro
de un diálogo.
Esta sección explica estos tópicos:
● ColorChooserDemo: Toma 2
● Mostrar un ColorChooser en un diálogo
● Reemplazar o Eliminar el panel de Previsionado
● Crear un Panel Selector Personalizado
● El API ColorChooser
● Ejemplo que utilizando Selectores de Color
ColorChooserDemo: Toma 2
if (newColor != null) {
banner.setTextColor(newColor);
}
JColorChooser proporciona otro método que nos ayuda a utiliza un selector
de color en un diálogo. El método createDialog crea y devuelve un diálogo,
permitiendo especificar los oyentes de action para los botones OK y Cancel
de la ventana de diálogo. Se utiliza el método show de JDialog para
mostrar el diálogo creado con este método.
colorChooser.setPreviewPanel(new JPanel());
Efectivamente, esto elimina el panel de previsionado porque un JPanel
plano no tiene tamaño ni vista por defecto.
Para proporcionar un panel de previsionado personalizado, también
podemos utilizar setPreviewPanel. El componente que pasemos dentro del
método debería descender de JComponent, especificar un tamaño
razonable, y proporcionar una vista personalizada del color actual (obtenida
con el método getColor de Component getColor). De hecho, después de
añadir un método getPreferredSize a Banner, podríamos utilizar un
ejemplar de Banner como panel de previsionado.
colorChooser.addChooserPanel(new CrayonPanel());
El API ColorChooser
● Personalizar un ColorChooser
● Seleccionar u Obtener la Selección Actual
Crear y Mostrar un ColorChooser
Método Propósito
Crea un selector de color.
El constructor por defecto
crea un selector de color
con el color inicial blanco.
Se utiliza el segundo
JColorChooser() constructor para
JColorChooser(Color) especificar un color inicial
JColorChooser(ColorSelectionModel) diferente. El argumento,
ColorSelectionModel,
cuando está presente,
proporciona un selector de
color con un modelo de
selección de color.
Crea y muestra un selector
de color en un diálogo
modal. El argumento
Component es el padre
Color showDialog(Component, String,
del diálogo, el argumento
Color)
String específica el título
del diálogo, y el
argumento Color el color
seleccionado inicialmente.
Crea un diálogo para el
selector de color
especificado. Como en
showDialog, el
argumento Component es
el padre del diálogo y el
JDialog createDialog(Component, String,
argumento String
boolean, JColorChooser, ActionListener,
específica el título del
ActionListener)
diálogo. El argumento
boolean especifica si el
diálogo es modal. El primer
ActionListener es para el
botón OK, y el segundo
para el botón Cancel.
Personalizar un ColorChooser
Método Propósito
Selecciona u
obtiene el
componente
utilizado para
previsionar la
selección de
color. Para
eleminar el
void setPreviewPanel(JComponent) panel de
JComponent getPreviewPanel() previsionado,
se utiliza new
JPanel().
Para
especificar el
panel de
previsionado
por defecto,
se utiliza null.
Selecciona u
obtiene los
void setChooserPanels(AbstractColorChooserPanel[]) paneles
AbstractColorChooserPanel[] getChooserPanels() selectores en
el selector de
color.
Añade o
void addChooserPanel(AbstractColorChooserPanel) elimina un
AbstractColorChooserPanel panel selector
removeChooserPanel(AbstractColorChooserPanel) en el selector
de color.
Seleccionar u Obtener la Selección Actual
Método Propósito
Selecciona u obtiene el
color seleccionado
actualmente. Los tres
argumentos enteros de
setColor especifican los
valores RGB del color. El
void setColor(Color)
único argumento entero
void setColor(int, int, int)
de setColor también
void setColor(int)
específica el color en
Color getColor()
RGB. Los 8 bits de
mayor peso especifican
el rojo, los 8 bits
siguientes el verde, y
los 8 bits de menor peso
el azul.
Selecciona u obtiene el
modelo de selección
para el selector de
color. Este objeto
void setSelectionModel(ColorSelectionModel)
contiene la selección
ColorSelectionModel getSelectionModel()
actual y dispara eventos
change para los oyentes
registrados si la
selección cambia.
Aquí puedes ver una imagen de una aplicación que utiliza un ComboBox editable
para introducir un patrón con el que formatear fechas.
Intenta esto:
1. Compila y ejecuta el ejemplo:
ComboBoxDemo.java.
2. Introduce un nuevo patrón
eligiendo uno de la lista
desplegable. El programa
reformatea la fecha y hora
actuales.
3. Introduce un nuevo patrón
tecleándolo y pulsando
return. De nuevo el
programa reformatea la fecha
y hora actuales.
String[] patternExamples = {
"dd MMMMM yyyy",
"dd.MM.yy",
"MM/dd/yy",
"yyyy.MM.dd G 'at' hh:mm:ss z",
"EEE, MMM d, ''yy",
"h:mm a",
"H:mm:ss:SSS",
"K:mm a,z",
"yyyy.MMMMM.dd GGG hh:mm aaa"
};
currentPattern = patternExamples[0];
. . .
JComboBox patternList = new JComboBox(patternExamples);
patternList.setEditable(true);
patternList.setSelectedIndex(0);
patternList.setAlignmentX(Component.LEFT_ALIGNMENT);
PatternListener patternListener = new PatternListener();
patternList.addActionListener(patternListener);
Este programa proporciona los valores para la lista desplegable del ComboBox con
un array de strings. Sin embargo, los valores de la lista pueden ser cualquier
Object, en cuyo caso el método toString de la clase Object proporciona el texto a
mostrar. Para poner una imagen u otro valor que no sea texto en una lista
ComboBox, sólo debemos proporcionar un celda personalizada renderizada con
setRenderer.
Observa que el código activa explícitamente la edición para que el usuario pueda
teclear valores. Esto es necesario porque, por defecto, un ComboBox no es
editable. Este ejemplo particular permite editar el ComboBox porque su lista no
proporciona todos los patrones de formateo de fechas posibles.
El código también registra un oyente de action con el ComboBox. Cuando un
usuario selecciona un ítem del ComboBox, se llama a este método:
Intenta esto:
1. Compila y ejecuta el
programa:
ComboBoxDemo2.java.
También necesitarás 5
ficheros de imágenes:
Bird.gif, Cat.gif, Dog.gif,
Rabbit.gif, and Pig.gif.
2. Eleige una mascota desde la
lista desplegable para ver su
dibujo.
3. Cómo usar Radio Buttons
proporciona una versión de
este programa,
RadioButtonDemo.java,
que utiliza un grupo de
botones de rádio en lugar de
un ComboBox. Compila y
ejecuta el programa.
Compara el código fuente y la
operación de los dos
programas.
...
//in the ComboBoxDemo2 constructor
String[] petStrings = { "Bird",
"Cat",
"Dog",
"Rabbit",
"Pig" };
// Crea el combobox,
// desactiva la edición
// y selecciona el primero
JComboBox petList = new JComboBox(petStrings);
petList.setSelectedIndex(0);
Este código es similar al código de ComboBoxDemo. Sin embargo, este
programa deja el ComboBox no editable (por defecto).
Se utiliza un ComboBox no editable en lugar de un grupo de botones de
radio para mostrar una o más elecciones en estas situaciones:
● Cuando el espacio es limitado
El API ComboBox
Cuando se pulsa el botón Open el programa trae un open file chooser. Cuando se
pulsa el botón Save el programa trae un save file chooser. Aquí podemos ver una
imagen de un selector de apertura de ficheros:
Aquí podemos ver el código que crea y muestra el selector de apertura de ficheros:
if (returnVal == JFileChooser.APPROVE_OPTION) {
File file = filechooser.getSelectedFile();
log.append("Saving: " + file.getName() + "." + newline);
} else {
log.append("Save command cancelled by user." + newline);
}
}
Utilizando el mismo selector de ficheros para abrir y grabar ficheros, el programa
consigue estos beneficios:
● El selector recuerda el directorio actual entre usos, por eso los diálogos de
abrir y grabar comparten el mismo directorio actual.
● Sólo tenemos que personalizar un selector de ficheros, y nuestra
personalización se aplicará a las dos versiones, la de apertura y la de
grabación.
Cómo hemos podido ver en los fragmentos de código anteriores, los métodos
showXxxxDialog devuelven un entero que indica si el usuario ha seleccionado un
fichero. Podemos utilizar el valor de retorno para determinar si realizar o no la
operación requerida.
Si el usuario elige un fichero, el código llama a getSelectedFile sobre el selector
de ficheros para obtener un ejemplar de File, que representa el fichero elegido. El
ejemplo obtiene el nombre del fichero y lo utiliza en un mensaje. Podemos utilizar
otros métodos del objeto File, como getPath o isDirectory, para obtener
información sobre él. También podemos llamar a otros métodos como delete y
rename para cambiar el fichero de alguna forma. Por supuesto, podríamos leer o
grabar el fichero utilizando una de las clases lectoras o escritoras proporcionadas
por el JDK.
Si quieres crear un selector de ficheros para una tarea distinta de abrir o grabar, o
si quieres personalizar el selector de ficheros, sigue leyendo. Estos excitantes
tópicos se describen más abajo:
● FileChooserDemo: Toma 2
FileChooserDemo: Toma 2
filechooser.addChoosableFileFilter(new ImageFilter());
El filtro personalizado se implementa en ImageFilter.java, como
una sublcase de FileFilter. La clase ImageFilter implementa el
método getDescription para devolver un string y ponerlo en la
lista de filtros seleccionables. Como muestra el siguiente código,
ImageFilter implementa el método accept para aceptar todos los
directorios y cualquier fichero que tenga las extensiones ".jpg",
".jpeg", ".gif", ".tif", or ".tiff".
if (f.isDirectory()) {
return true;
}
String s = f.getName();
int i = s.lastIndexOf('.');
return false;
}
Aceptando todos los directorios, este filtro permite al usuario
navegar a través del sistema de ficheros. Si se omitieran las líneas
en negrita de este método, el usuario se vería limitado al directorio
en que se inicializó el selector de ficheros.
filechooser.setFileView(new ImageFileView());
ImageFileView muestra un icono diferente para cada tipo de imagen
aceptada por el filtro de imágenes descrito anteriormente.
La clase ImageFileView sobreescribe los cinco métodos abstractos
definidos en FileView:
String getTypeDescription(File f)
Devuelve una descripción del tipo de fichero. Aquí podemos ver la
implementación e este método en ImageFileView:
if (extension != null) {
if (extension.equals("jpeg")) {
type = "JPEG Image";
} else if (extension.equals("gif")){
type = "GIF Image";
} else if (extension.equals("tiff")) {
type = "TIFF Image";
}
}
return type;
}
Icon getIcon(File f)
Devuelve un icono que representa el fichero o su tipo. Aquí tenemos
la implementación de este método en ImageFileView:
filechooser.setAccessory(new ImagePreview(filechooser));
Cualquier objeto que desciende de JComponent puede ser un accesorio
de visionado. El componente debería implementar paint o
paintComponent, y tener un tamaño predeterminado que parezca
adecuado en el selector de ficheros.
El selector de ficheros dispara un evento de cambio de propiedad cuando
el usuario selecciona un ítem de la lista. Por eso, un programa con
accesorio de visionado debe registrarse para recibir estos eventos y
actualizarse cada vez que la selección cambie. En el ejemplo, el propio
objeto ImagePreview se registra para estos eventos. Esto mantiene en
una sola clase todo el código relacionado con el accesorio de visionado.
Aquí podemos ver la implementación del método propertyChange en el
ejemplo, que es el método llamado cuando se dispara un evento de
cambio de propiedad:
El API de FileChooser
Intenta esto:
1. Compila y ejecuta la aplicación. El código fuente está en
LabelDemo.java, y la imagen en middle.gif.
2. Redimensiona la ventana para poder ver cómo los contenidos de las
etiquetas se sitúan con las áreas de dibujo.
Todos los contenidos de las etiquetas tienen el alineamiento vertical
por defecto -- los contenidos están centrados verticalmente en el
área de la etiqueta. La etiqueta superior que contiene texto e
imagen, tiene alineamiento horizontal centrado. La segunda
etiqueta, que sólo tiene texto, tiene alineamiento a la izquierda que
es por defecto para las etiquetas de sólo texto. La tercera etiqueta,
que contiene sólo una imagen, tiene alineamiento horizontal
centrado, que es por defecto para las etiquetas sólo de imágenes.
Abajo puedes ver el código de LabelDemo.java que crea las etiquetas del ejemplo
anterior.
ImageIcon icon = new ImageIcon("images/middle.gif");
. . .
label1 = new JLabel("Image and Text",
icon,
JLabel.CENTER);
//Set the position of the text, relative to the icon:
label1.setVerticalTextPosition(JLabel.BOTTOM);
label1.setHorizontalTextPosition(JLabel.CENTER);
El API Label
Además de las listas, los siguientes componentes Swing también presentan múltiples
ítems seleccionables al usuario: check boxes, combo boxes,menus, radio buttons, y
tables. Sólos los checkbox, las tablas, y las listas permiten seleccionar varios ítems a la
vez.
Aquí podemos ver una imagen de una aplicación que utiliza JList para mostrar los
nombres de las imágenes a ver.
Intenta esto:
1. Compila y ejecuta la aplicación. El código fuente está en
SplitPaneDemo.java. imagenames.properties proporciona los
nombres de las imágenes para ponerlos en el JList.
2. Elige una imagen de la lista. Utiliza las barras de desplazamiento para
ver más nombres.
No importa el modo de selección que utiliza la lista, siempre dispara eventos "list
selection" cuando cambia la selección. Se pueden procesar esos eventos añadiendo un
Oyente de "list selection" a la lista con el método addListSelectionListener.
El API List
Muchas de las operaciones de una lista están manejadas por otros objetos.
Por ejemplo, los ítems de la lista están manejados por un objeto ListModel, la
selección está manejada por un objeto ListSelectionModel, y la mayoría de los
programas ponen una lista en un panel desplazable para menajar el
desplazamiento. No tenemos que preocuparnos de la mayor parte de estos
objetos auxiliares, porque JList los crea cuando son necesarios, y nosotros
interactuamos con ellos implicitamente con los métodos de conveniencia de
JList.
Cómo se ha dicho, el API para utilizar Lists de divide en estas categorías:
● Seleccionar los ítems de una Lista
Esta tabla muestra ejemplos que utilizan JList y dónde poder encontrarlos.
Ejemplo Dónde se Describe Notas
En esta página y en
SplitPaneDemo.java Cómo usar Contiene una sencilla lista de
selección.
SplitPane
Cómo usar Implementa un diálogo modal
ListDialog.java con una sencilla lista de
BoxLayout
selección.
Contiene una lista y una tabla
Cómo escribir un que comparten el mismo
ListSelectionDemo.java oyente de 'List modelo de selección. El
Selection' modelo de selección se puede
cambiar dinámicamente.
Swing
Los menús son únicos en que, por convención, no se sitúan con los otros componentes en el UI. En su
lugar, aparecen en una barra de menú o en un menú desplegable. Una barra de menú contiene
uno o más menús, y tiene una posición dependiente de la plataforma -- normalmente debajo de la
parte superior de la ventana. Un menú desplegable es un menú que es invisible hasta que el usuario
hace una acción del ratón específica de la plataforma, como pulsar el botón derecho del ratón sobre
un componente. Entonces el menú desplegable aparece bajo el cursor.
La siguiente figura muestra los componentes Swing que implementan cada parte de un sistema de
menús.
El resto de esta sección nos enseña los componentes de menú y nos dice cómo utilizar varias de sus
características:
● La herencia de componentes menú
● Crear menús
● Manejar Eventos desde ítems de menú
● Traer un Menú desplegable
● Personalizar un Menú
● El API Menu
● Ejemplos que utilizan Menús
Aquí podemos ver el árbol de herencia de las clases relacionadas con los menús:
Como se ve en la figura, los ítems de menús (incluidos los propios menús) son simples
botones. Podríamos preguntarnos como un menú, si es sólo un botón, muestra sus ítems.
La respuesta es que cuando se activa un menú, automáticamente trae un menú desplegable
que muestra sus ítems.
Crear Menús
Aquí está el código que crea los menús mostrados al principio de esta página. Puedes
encontrar el programa completo en MenuLookDemo.java. Para ejecutarlo, necesitas tener
el fichero de imagen: images/middle.gif. Como este código no tiene manejo de eventos,
los menús no hacen nada útil, excepto verse como serían. Si ejecutamos el ejemplo,
observaremos que a pesar de no tener un manejo de eventos, los menús y submenús
aparecen cuando deben, y los checkbox y los botones de radio responden apropiadamente
cuando el usuario los elige.
//a submenu
menu.addSeparator();
submenu = new JMenu("A submenu");
menuItem = new JMenuItem("An item in the submenu");
submenu.add(menuItem);
menuItem = new JMenuItem("Another item");
submenu.add(menuItem);
menu.add(submenu);
Para detectar cuando el usuario selecciona un JMenuItem, se puede escuchar por eventos
action (igual que se haría para un JButton). Para detectar cuando el usuario selecciona un
JRadioButtonMenuItem, se puede escuchar tanto por eventos action, como por eventos
item, como se describio en Cómo usar Radio Buttons. Para JCheckBoxMenuItems,
generalmente se escuchan eventos de item, como se describió en Cómo usar CheckBox.
Las ventanas desplegables de peso ligero son más eficientes que las ventanas de peso
pesado, pero no funcionan bien si tenemos componentes pesados dentro de nuestro GUI.
Especificamente, cuando un área de una ventana desplegable de peso ligero se
intersecciona con un componente de peso pesado, el componente de peso pesado se dibuja
encima. Esta es una de las razones porla que recomendamos no mezclar componentes de
peso ligero y de peso pesado. Si realmente necesitamos utilizar un componente de peso
pesado en nuestro GUI, podemos utilizar el método setLightWeightPopupEnabled de
JPopupMenu para desactivar las ventanas desplegables de peso ligero. Para más detalles
puedes ver el artículo Mezclar componentes de peso ligero y pesado, de La conexión Swing.
(En inglés).
El API de JMenu
Las siguientes tablas listan los métodos y constructores más utilizados de Jmenu. El API se
divide en estas categorías:
● Crear y Configurar Barras de Menú
Aquí podemos ver una imagen de una pequeña aplicación que utiliza una
barra de progreso para medir el progreso de una tarea que se ejecuta:
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
ProgressBarDemo.java. También necesitarás
LongTask.java y SwingWorker.java.
2. Pulsa el botón Start. Mira la barra de progreso mientras la
tarea progresa. La tarea muestra su salida en el área de texto
en la parte inferior de la ventana.
progressMonitor.setNote(task.getMessage());
progressMonitor.setProgress(task.getCurrent());
● Los últimos dos argumentos proporcionan los valores mínimo y máximo,
respectivamente, para la barra de progreso mostrada en el diálogo.
Después el ejemplo crea el monitor de progreso, y lo configura:
progressMonitor.setProgress(0);
progressMonitor.setMillisToDecideToPopup(2 * ONE_SECOND);
La primera línea selecciona la posición actual de la barra de progreso del
diálogo. La segunda indica que el monitor debería desplegar un diálogo si la
tarea se ejecuta durante más de dos segundos.
Por el simple echo de que este ejemplo utiliza un monitor de progreso, añade
una característica que no estaba presente en la versión del programa que
utiliza una barra de progreso. El usuario puede cancelar la tarea pulsando el
botón Cancel del diálogo. Aquí tenemos el código del ejemplo que chequea si
el usuario cancela la tarea o si la tarea sale normalmente:
if (progressMonitor.isCanceled() || task.done()) {
progressMonitor.close();
task.stop();
Toolkit.getDefaultToolkit().beep();
timer.stop();
startButton.setEnabled(true);
}
Observa que el monitor de progreso no cancela por si mismo la tarea.
Proporciona el GUI y el API para permitir que el programa lo haga facilmente.
El API de ProgressBar
Aquí podemos ver una imagen de una aplicación que utiliza cinco botones de radio
para elegir qué tipo de mascota mostrar:
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
RadioButtonDemo.java. También necesitarás cinco ficheros de
imágenes: Bird.gif, Cat.gif, Dog.gif, Rabbit.gif, y Pig.gif.
2. Pulsa el botón 'Dog' o pulsa Alt-d.
El botón 'Dog' de selecciona, lo que hace que el botón 'Bird' sea
deselecciondo. La imagen cambia de un pájaro a un perro. Esta
aplicación tiene un oyente de action que escucha todos los botones
de radio. Cada vez que el oyente de action recibe un evento, la
aplicación muestra la imagen del botón de radio que ha sido
seleccionado.
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es SliderDemo.java. También
necesitarás las 16 imágenes del directorio example-swing/images que
empiezan con "burger".
2. Utiliza el Slider para ajustar la velocidad de animación.
framesPerSecond.setPaintLabels(true);
framesPerSecond.setBorder(BorderFactory.createEmptyBorder(0,0,0,10));
Este código crea explícitamente un Hashtable y lo rellena con los valores de las
etiquetas y sus posiciones. Cada valor de etiqueta debe ser un Component y en
este programa, son simples etiquetas de texto. También podemos utilizar
etiquetas con iconos. Si queremos etiquetas numéricas posicionadas a intervalor
específicos, podemos utilizar el método createStandardLabels de JSlider.
El API Slider
Las siguiente tablas listan los métodos y constructores más utilizados de JSlider.
Otros métodos interesantes son definidos por las clases JComponent y Component.
El resto de esta página explica como realizar algunas de las tareas más comunes
relacionadas con las tablas. Aquí están los tópicos cubiertos por está página:
● Crear una Tabla Sencilla
Object[][] data = {
{"Mary", "Campione",
"Snowboarding", new Integer(5), new Boolean(false)},
{"Alison", "Huml",
"Rowing", new Integer(3), new Boolean(true)},
{"Kathy", "Walrath",
"Chasing toddlers", new Integer(2), new Boolean(false)},
{"Mark", "Andrews",
"Speed reading", new Integer(20), new Boolean(true)},
{"Angela", "Lih",
"Teaching high school", new Integer(4), new Boolean(false)}
};
● Tratan igual a todos los tipos de datos. Por ejemplo, si una columna tiene
datos Boolean, los datos pueden mostrarse como un CheckBox en la tabla.
Sin embargo, si especificamos los datos como un argumento array o vector
del constructor de JTable, nuestro dato Boolean se mostrará como un
string. Se pueden ver estas diferencias en las dos últimas columnas de los
ejemplos ateriores.
● Requieren que pongamos todos los datos de la tabla en un array o vector, lo
que es inapropiado para algunos datos. Por ejemplo, si estamos
ejemplarizando un conjunto de objetos desde una base de datos, podríamos
quere pedir los objetos directamente por sus valores, en vez de copiar todos
los valores en un array o un vector.
Si queremos evitar estas restricciones, necesitamos implementar nuestro propio
modelo de tabla como se describe en Crear un Modelo de Tabla.
Es fácil poner una tabla en un ScrollPane. Sólo necesitamos escribir una o dos
líneas de código:
container.setLayout(new BorderLayout());
container.add(table.getTableHeader(), BorderLayout.NORTH);
container.add(table, BorderLayout.CENTER);
Por defecto, todas las columnas de una tabla empiezan con la misma anchura, y
las columnas rellenan automáticamente la anchura completa de la tabla. Cuando la
tabla se ensancha o se estrecha (lo que podría suceder cuando el usuario
redimensiona la ventana que la contiene) la anchura de todas las columnas cambia
apropiadamente.
Cuando el usuario redimensiona una columna, arrastando su borde derecho, todas
las demás deben cambiar su tamaño. Por defecto, el tamaño de la tabla permace
igual, y todas las columnas a la derecha del punto de arrastre acomodan su
tamaño al espacio añadido o eliminado desde la columna situada a la izquierda del
punto de arrastre.
Las siguientes figuras ilustran el comportamiento de redimensionado por defecto.
Como muestra el código anterior, cada columna de la tabla está representada por
un objeto TableColumn. Junto a setPreferredWidth, TableColumn también
suministra métodos para obtener la anchura mínima, máxima y actual de una
columna. Para un ejemplo de selección de anchura de celdas basada en la
cantidad de espacio necesario para mostrar el contenido de las celdas, puedes ver
el método initColumnSizes en TableRenderDemo.java, que se explica en
Mayor personalización del Visionado y del manejo de Eventos.
Cuando el usuario redimensiona explícitamente las columnas, los nuevos tamaños
no sólo se convierten en la anchura actual de la columna, sino que también se
convierten en la anchura preferida. Si embargo, cuando las columnas se
redimensionan como resultado de un cambio de anchura de la tabla, las anchuras
preferidas de las columnas no cambian.
Podemos cambiar el comportamiento de redimensionado de una tabla llamando al
método setAutoResizeMode. El argumento de este método debe ser uno de
estos valores (definidos como constantes en JTable):
AUTO_RESIZE_SUBSEQUENT_COLUMNS
Por defecto. Además de redimensionar la columna a la izquierda del punto de
arrastre, ajusta los tamaños de todas las columnas situadas a la derecha del
punto de arrastre.
AUTO_RESIZE_NEXT_COLUMN
Ajusta sólo las columnas inmediatas a la izquierda y derecha del punto de
arrastre.
AUTO_RESIZE_OFF
Ajusta el tamaño de la tabla.
Nota: Antes de la versión Swing 1.1 Beta, el modo por defecto era
AUTO_RESIZE_ALL_COLUMNS. Sin embargo, este modo no es
intuitivo por eso se cambió el modo por defecto a:
AUTO_RESIZE_SUBSEQUENT_COLUMNS.
table.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
...
ListSelectionModel rowSM = table.getSelectionModel();
rowSM.addListSelectionListener(new ListSelectionListener() {
public void valueChanged(ListSelectionEvent e) {
ListSelectionModel lsm = (ListSelectionModel)e.getSource();
if (lsm.isSelectionEmpty()) {
...//no rows are selected
} else {
int selectedRow = lsm.getMinSelectionIndex();
...//selectedRow is selected
}
}
});
SimpleTableSelectionDemo también tiene código (no incluido en el fragmento
anterior) que cambia la orientación de la selección de la tabla. Cambiando un par
de valores booleanos, podemos permitir que la tabla acepte selecciones de
columnas o de celdas individuales en vez de seleccionar filas.
Para más información y ejemplos de implementación de selecciones, puedes ver
Escribir un Oyente de List Selection.
Como se ha visto, toda tabla obtiene sus datos desde un objeto que implemente el
interface TableModel.
new AbstractTableModel() {
public String getColumnName(int col) {
return columnNames[col].toString();
}
public int getRowCount() { return rowData.length; }
public int getColumnCount() { return columnNames.length; }
public Object getValueAt(int row, int col) {
return rowData[row][col];
}
public boolean isCellEditable(int row, int col) { return true; }
public void setValueAt(Object value, int row, int col) {
rowData[row][col] = value;
fireTableCellUpdated(row, col);
}
}
Cómo muestra el código anterior, implementar un modelo de tabla puede ser
sencillo. Generalmente, se implementa en una subclase de la clase
AbstractTableModel.
public TableDemo() {
...
MyTableModel myModel = new MyTableModel();
JTable table = new JTable(myModel);
table.setPreferredScrollableViewportSize(new Dimension(500, 70));
/*
* Don't need to implement this method unless your table's
* editable.
*/
public boolean isCellEditable(int row, int col) {
//Note that the data/cell address is constant,
//no matter where the cell appears onscreen.
if (col < 2) {
return false;
} else {
return true;
}
}
/*
* Don't need to implement this method unless your table's
* data can change.
*/
public void setValueAt(Object value, int row, int col) {
...//debugging code not shown...
...//ugly class cast code for Integers not shown...
data[row][col] = value;
...//debugging code not shown...
}
...
Antes de seguir adelante, necesitamos comprender como las tablas dibujan sus
celdas. Podríamos esperar que cada celda de la tabla fuera un componente. Sin
embargo, por razones de rendimiento, las tablas Swing no están implementadas
de esta forma.
En su lugar, se utiliza un sencillo intérprete de celdas para dibujar todas las
celdas de una columna. Frecuentemente este intérprete es compartido entre todas
las columnas que contienen el mismo tipo de datos. Podemos pensar en el
intérprete como un sello de caucho que las tablas utilizan para estampar los datos
formateados apropiadamente en cada celda. Cuando el usuario empieza a editar
los datos de una celta, un editor de celdas toma el control sobre la edición de la
celda.
Por ejemplo, todas las celdas de la columna '# of Years' de TableDemo contienen
datos numéricos -- específicamente un objeto Integer. Por defecto, el intérprete
para una columna numérica utiliza un sencillo ejemplar de JLabel para dibujar los
números apropiados, alineados a la derecha, en las celdas de la columna. Si el
usuario empieza a editar una de las celdas, el editor por defecto utiliza un
JTextField alineado a la derecha para controlar la edición.
Para elegir el intérprete que muestra la celdas de una columna, una tabla primero
determina si hemos especificado un ínterprete para esa columna particular. Si no
lo hacemos, la tabla llama al método getColumnClass del modelo de tabla, que
obtiene el tipo de datos de las celdas de la columna. Luego, la tabla compara el
tipo de datos de la columna con una lista de tipos de datos para los que hay
registrados unos intérpretes. Esta lista es inicializada por la tabla, pero podemos
añadirle elementos o cambiarla. Actualmente, las tablas ponen los siguientes tipos
en la lista:
● Boolean -- interpretado con un checkbox.
● Object -- interpretado por una etiqueta que muestra el valor String del
objeto.
Las tablas eligen sus editores de celdas utilizando un algoritmo similar.
Recuerda que si dejamos que una tabla cree su propio modelo, utiliza Object
como el tipo de cada columna. TableDemo.java muestra como especificar los
tipos de datos de las columnas con más precisión.
Las siguientes secciones explican cómo pesonalizar el visionado y edición de celdas
especificando intérpretes y editores de celdas para columnas o tipos de datos.
En los ejemplos de tablas que hemos visto hasta ahora, el usuario podía introducir
cualquier texto en la columna '# of Years'. SimpleTableDemo no comprueba el
valor de los datos. El ejemplo TableDemo está ligeramente mejorado en que
cuando el usuario hace la edición, el código comprueba si la entrada puede ser
pasada a un entero. Sin embargo, TableDemo debe usar un código más ambicioso
para convertir el string devuelto por el editor de celdas por defecto en un Integer.
Si no hace la conversión, el tipo real de los datos podría cambiar de Integer a
String.
Lo que realmente queremos hacer es comprobar la entrada del usuario mientras
la está tecleando, y hacer que el editor de celdas devuelva un Integer en lugar de
un string. Podemos conseguir una o estas dos tareas utilizando un campo de texto
personalizado para controlar la edición de la celda.
Un campo de texto personalizado, puede chequear la entrada del usuario mientras
la está tecleando o después de que haya indicado el final (pulsado la tecla return,
por ejemplo). Llamamos a estos tipos de validación, chequeo de pulsación y
chequeo de acción, respectivamente.
El siguiente código, tomado de TableEditDemo.java, configura un campo de
texto con chequeo de pulsación. Las líneas en negrita hacen que el campo de texto
sea el editor para todas las celdas que contengan datos del tipo Integer.
DefaultCellEditor integerEditor =
new DefaultCellEditor(integerField) {
//Override DefaultCellEditor's getCellEditorValue method
//to return an Integer, not a String:
public Object getCellEditorValue() {
return new Integer(integerField.getValue());
}
};
table.setDefaultEditor(Integer.class, integerEditor);
La clase WholeNumberField utilizada arriba es una subclase de JTextField
personalizada que permite al usuario introducir sólo dos dígitos. El método
getValue devuelve el valor int del contenido de WholeNumberField Puedes ver
Cómo usar TextField para más información sobre WholeNumberField. Esta
página también proporciona un textfield con validación de propósito general,
llamado DecimalField, que podemos personalizar para validar cualquier formato
de número que le especifiquemos.
comp = column.getHeaderRenderer().
getTableCellRendererComponent(
null, column.getHeaderValue(),
false, false, 0, 0);
headerWidth = comp.getPreferredSize().width;
comp = table.getDefaultRenderer(model.getColumnClass(i)).
getTableCellRendererComponent(
table, longValues[i],
false, false, 0, i);
cellWidth = comp.getPreferredSize().width;
...//debugging code not shown...
column.setPreferredWidth(Math.max(headerWidth, cellWidth));
}
El API Table
Las tablas de esta sección sólo cubren una parte de este API. Para más
información puedes ver el API de JTable y para distintas clases y paquetes table
package. El API para usar tablas se divide en estas categorías:
● Clases e Interfaces Relacionados con las Tablas
● Crear y Configurar una Tabla
● Manipular Columnas
● Usar Editores e Intérprete
● Implementar Selección
Clases e Interfaces Relacionados con las Tablas
Clase/Interface Propósito
El componente que presenta la
JTable
tabla al usuario.
El componente que presenta
los nombres de columnas al
JTableHeader usuario. Por defecto, la tabla
genera este componente
automáticamente.
Respectivamente, el interface
que un modelo de tabla debe
TableModel, AbstractTableModel implementar y la superclase
usual para implementaciones
de modelos de tabla.
Respectivamente, el interface
TableCellRenderer, que un intérprete de celda
DefaultTableCellRenderer debe implementar y la
implementación más usual.
Respectivamente, el interface
TableCellEditor, DefaultCellEditor que debe implementar un
editor de celda, y la
implementación más usual.
Respectivamente, el interface
que debe implementar un
modelo de columna, y su
implementación usual.
TableColumnModel, Normalmente no tenemos que
tratar directamente con el
DefaultTableColumnModel
modelo de columna a menos
que necesitemos obtener el
modelo de selección de
columna u obtener un índice
de columna o un objeto.
Controla todos los atributos de
una columna de la tabla,
incluyendo, redimensionado,
TableColumn anchuras mínima, máxima,
preferida y actual; y
editor/intérprete opcional
específico de la columna.
Un modelo de tabla basado en
Vector utilizado por JTable
DefaultTableModel cuando construimos una tabla
sin especificar modelo de
datos ni datos.
Crear y Configurar una Tabla
Método/Constructor de JTable Propósito
Crea una tabla. El
argumento opcional
TableModel
especifica el modelo
que proporciona los
datos de la tabla. Los
argumentos
opcionales
TableColumnModel y
ListSelectionModel
JTable(TableModel) permiten especificar el
JTable(TableModel, TableColumnModel) modelo de columna y
JTable(TableModel, TableColumnModel, el modelo de
ListSelectionModel) selección. Como una
JTable() alternativa para
JTable(int, int) especificar un modelo
JTable(Object[][], Object[]) de tabla, podemos
JTable(Vector, Vector) suministrar datos y
nombres de columnas
utilizando un array o
un Vector. Otra
opción es no
especificar datos,
opcionalmente
especificar el número
de filas y columnas
(ambos enteros) que
hayan en la tabla.
Selecciona el tamaño
de la parte visible de
void
la tabla cuando se
setPreferredScrollableViewportSize(Dimension)
está viendo dentro de
un ScrollPane.
Obtiene el
componente que
JTableHeader getTableHeader(Dimension)
muestra los nombres
de columnas.
Manipular Columnas
Método Propósito
TableColumnModel getColumnModel() Obtiene el modelo de columna de la
(en JTable) tabla.
TableColumn getColumn(int)
Obtiene uno o todos los objetos
Enumeration getColumns()
TableColumn de la tabla.
(en TableColumnModel)
void setMinWidth(int)
void setPreferredWidth(int) Seleciona la anchura mínima,
void setMaxWidth(int) preferida o máxima de la columna.
(en TableColumn)
int getMinWidth(int)
int getPreferredWidth()
Obtiene la anchura mínima, preferida,
int getMaxWidth()
máxima o actual de la columna.
int getWidth()
(en TableColumn)
Usar Editores e Intérpretes
Métodos Propósito
Selecciona el intérprete
o editor usado, por
void setDefaultRenderer(Class, TableCellRenderer) defecto, para todas las
void setDefaultEditor(Class, TableCellEditor) celdas en todas las
(en JTable) columnas que
devuelvan el tipo de
objetos especificado.
Selecciona el intérprete
void setCellRenderer(TableCellRenderer)
o editor usado para
void setCellEditor(TableCellEditor)
todas las celdas de esta
(en TableColumn)
columna.
Obtiene el intérprete de
TableCellRenderer getHeaderRenderer() cabecera para esta
(en TableColumn) columna, que podemos
personalizar.
Implementar Selección
Método de JTable Propósito
Selecciona los intervalos de selección
permitidos en la tabla. Los valores
válidos están definidos en
ListSelectionModel como
void setSelectionMode(int)
SINGLE_SELECTION,
SINGLE_INTERVAL_SELECTION, y
MULTIPLE_INTERVAL_SELECTION
(por defecto).
void
setSelectionModel(ListSelectionModel) Selecciona u obtiene el modelo usado
ListSelectionModel para controlar las selecciones de filas.
getSelectionModel()
Selecciona la orientación de selección
void
de la tabla. El argumento booleano
setRowSelectionAllowed(boolean)
especifica si está permitido el tipo de
void
selección particular. Por defecto, las
setColumnSelectionAllowed(boolean)
selección de filas está permitida, y la
void setCellSelectionEnabled(boolean)
de columna y celda no.
Esta tabla lista ejemplos que usan JTable y dónde poder encontrarlos.
Dónde se
Ejemplos Notas
Describe
Una tabla básica con un modelo no
personalizado. No incluye código
SimpleTableDemo.java Esta para: especificar anchuras de
página columna o detectar edición del
usuario.
Añade selección sencilla y detección
de selección a SimpleTableDemo.
Modificando las constantes
SimpleTable- ALLOW_COLUMN_SELECTION y
Esta
ALLOW_ROW_SELECTION del
SelectionDemo.java página
programa, podemos experimentar
con distintas alternativas para
permitir que sólo las filas sean
seleccionadas.
TableDemo.java Esta Una tabla básica con modelo
página personalizado.
Modifica TableDemo para usar un
TableEditDemo.java, Esta editor personalizado (una variante
WholeNumberField.java página de textfiled) para todos los datos
Integer.
Modifica TableDemo para usar un
editor personalizado (un combobox)
para todos los datos de la columna
TableRenderDemo.java Esta 'Sport'. También redimensiona
página inteligentemente los tamaños de las
columnas y utiliza un intérprete para
mostrar tool-tips para la celdas y la
cabecera de la columna 'Sport'.
Modifica TableEditDemo para tener
TableDialogEditDemo.java, un intérprete y un editor de cela que
Esta
muestre colores y nos permita elegir
WholeNumberField.java página
uno, utilizando un diálogo selector de
colores.
Ordena los datos interponiendo un
TableSorterDemo.java, manipulador de datos entre el
TableSorter.java, Esta
modelo de datos y la tabla. Detecta
página
TableMap.java las puslaciones del usuario sobre
cabeceras de columnas.
Escribir
un Muestra cómo utilizar todos los
ListSelectionDemo.java Oyente de modos de selección, usando un
oyente de list selection que se
List
comparte entre una tabla y una lista.
Selection
Swing
Un componente de texto
formateado puede mostrar y
editar texto usando más una
fuente. Algunos componentes
de texto formateado permiten
embeber imágenes e incluso
componentes. Típicamente se
tendrán que hacer más
programación para usar y
configurar componentes de
texto formateado, porque
muchas de sus
funcionalidades no están
disponibles a través de la JEditorPane
Formateado manipulación directa con el
y su subclase JTextPane
ratón y el teclado. Por
ejemplo, para soportar la
edición del estilo de texto,
tendremos que crear un
interface de usuario. Una
característica manejable y
fácil de usar proporcionada
por JEditorPane crea 'editor
panes' y 'text panes'
particularmente poderosos
para mostrar información de
ayuda no editable: pueden ser
cargados con texto
formateados desde una URL
String s = null;
try {
s = "file:"
+ System.getProperty("user.dir")
+ System.getProperty("file.separator")
+ "TextSamplerDemoHelp.html";
URL helpURL = new URL(s);
/* ... use the URL to initialize the editor pane ... */
} catch (Exception e) {
System.err.println("Couldn't create help URL: " + s);
}
Este código utiliza las propiedades del sistema para calcular un fichero
URL desde el fichero de ayuda. Por restricciones de seguridad, este código
no funcionará en la mayoría de los applets. En su lugar, utilizar el
codebase del applet para calcular una URL http.
Al igual que las áreas de texto, los editor pane normalmente son
manejados por un sroll pane:
String[] initStyles =
{ /* ... fill array with names of styles ... */ };
Esta sección utiliza la aplicación mostrada abajo para explorar cada una de estas capacidades.
La aplicación demo contiene un JTextPane-- una de las subclases de JTextComponent que
soporta texto formateado, iconos y componentes embebidos -- para ilustrar las capacidades,
heredadas por todas las subclases de JTextComponent. Para más información específica
sobre JTextPane pueder ver la página Cómo usar Editor Panes y Text Panes.
● Personalizar un Documento
● Escuchar los cambios de un Documento
● Sobre los Kits de Edición
● Asociar Acciones con menús y botones
● Sobre los Mapas de teclado
● Associar Acciones con pulsaciones de teclas
● Implementar deshacer/repetir
● Escuchar los cambios de cursor y de selección
Personalizar un Documento
Recuerda que el documento para este text pane limita el número de caracteres
permitidos en el decumento. Si intentas añadir texto hasta exceder el límite
máximo, el documento bloquea el cambio y no se llamará al método insertUpdate
del oyente. Los oyentes de Document sólo son notificados si el cambio ha ocurrido
realmente.
Algunas veces, podrías estar tentado de cambiar el texto del documento desde
dentro de un oyente de Document. Por ejemplo, si tienes un campo de texto sólo
debería contener enteros y el usuario introduce algún otro tipo de datos, podrías
querer cambiar el texto a 0. Sin embargo, nunca se debe modificar el
contenido de un componente de texto desde dentro de un oyente de
Document. De hecho, si intentas hacerlo, tu programa se quedará bloqueado. En su
lugar proporciona un documento personalizado y sobreescribe los métodos insert y
remove. Crear un Campo de texto validado te enseña como hacerlo.
Cada componente de texto tiene uno o más keymaps-- cada uno de los cuales es un
ejemplar de la clase Keymap. Un keymap contiene una colección de parejas
nombre-valor donde el nombre es un KeyStroke (pulsación de tecla) y el valor es
una Action. Cada parej enlaza el keystroke con la acción por lo tanto cada vez que
el usuario pulsa la tecla, la acción ocurrirá.
Por defecto, un componente de texto tiene un keymap llamado
JTextComponent.DEFAULT_KEYMAP. Este keymap contiene enlaces básicos
estándars. Por ejemplo, las teclas de flechas están mapeadas para mover el cursor,
etc. Se puede modificar o ampliar el kjeymap por defecto de las siguientes formas:
● Añadiendo un keymao personalizado al componente de texto con del método
addKeymap de JTextComponent.
● Añadiendo enlaces de teclas al keymap por defecto con el método
addActionForKeyStroke de Keymap. El Keymap por defecto es compartido
entre todos los componentes de texto, utilizalo con precaución.
● Eliminado enlaces de teclas del keymap por defecto con el método
removeKeyStrokeBinding de Keymap. El Keymap por defecto es compartido
entre todos los componentes de texto, utilizalo con precaución.
Cuando se resuelve una pulsación a su acción, el componente de texto chequea el
keymap en el orden en que fueron añadidos al componente de texto. Así, el enlace
para una pulsación específica en un keymap que hayamos añadido a un componente
de texto sobreescribe cualquier enlace para la misma pulsación en el keymap por
defecto.
lpd.addUndoableEditListener(new MyUndoableEditListener());
El oyente usado en nuestro ejemplo añade la edición a la lista del undomanager:
Si queremos un campo de texto que también proporcione un menú de cadenas desde la que
elegir una, podemos considerar la utilización de un combo box editable. Si necesitamos
obtener más de una línea de texto desde el usuario deberíamos utilizar una de las glases que
implementan text area para propósito general.
El Applet siguiente muestra un campo de texto básico y un área de texto. El campo de texto
es editable y el áera de texto no lo és. Cuando el usuario pulse Return en el campo de texto,
el campo dispara un action event. El applet reacciona al evento copiando el contenido del
campo de texto en el área de texto y seleccionando todo el texto del campo de texto.
Esta es una imagen del GUI del applet. Para ejecutar el applet, pulsa sobre la
imagen. El Applet aparecerá en una nueva ventana del navegador.
Puedes encontrar el programa fuente en TextDemo.java. Aquí está el código de TextDemo
que crea el campo de texto del applet:
Prueba esto:
1. Compila y ejecuta la aplicación. El fichero fuente es
TextFieldDemo.java. También necesitarás
WholeNumberField.java, DecimalField.java, y
FormattedDocument.java.
2. Introduce la información en los campos de texto y mira los
resultados.
Si intentas introducir un campo no válido, el programa pitará.
3. Intenta teclear algo en el cuarto campo de texto.
No puedes, porque no es editable; sin embargo si se puede
seleccionar el texto.
4. Redimensiona la ventana.
Observa como las etiquetas y los campos de texto permanecen
alienados. Distribuir Parejas de Etiqueta/campo de Texto te contará
más cosas sobre esta característica del programa.
percentFormat = NumberFormat.getNumberInstance();
percentFormat.setMinimumFractionDigits(3);
Como muestra el código, la misma clase (NumberFormat) puede soportar
diferentes formatos. Además, Format y sus subclases son sensitivas a la localidad,
por eso un campo decimal, puede hacerse para soportar formatos de otros paises y
regiones. Puedes referirte a Formateando ien la sección de Internacionalización
para información más detallada sobre los formatos.
Aquí está la implementación que FormattedDocument hace de insertString:
try {
format.parseObject(proposedResult);
super.insertString(offs, str, a);
} catch (ParseException e) {
Toolkit.getDefaultToolkit().beep();
System.err.println("insertString: could not parse: "
+ proposedResult);
}
}
El método usa el formato para analizar el resultado de la inserción propuesta. Si el
resultado se formatea adecuadamente, el método llamada al método insert de su
superclase para hacer la inserción. Si el resultado no se formatea de la forma
decuada, el ordenador pita.
Además de sobreescribir el método insertString, FormattedDocument también
sobreescribe el método remove:
try {
if (proposedResult.length() != 0)
format.parseObject(proposedResult);
super.remove(offs, len);
} catch (ParseException e) {
Toolkit.getDefaultToolkit().beep();
System.err.println("remove: could not parse: " + proposedResult);
}
}
La implementación que FormattedDocument hace del método remove es similar
a su implementación del método insertString. El formato analiza el resultado del
cambio propuesto, y realiza la eliminación o no, dependiendo de si el resultado es
válido.
Nota: La solución propuesta en este ejmplo no es una solución general
para todos los tipos de formatos. Algunos formatos puede ser
validados-por-pulsación simplemente llamando al método parseObject.
Aquí tenemos un ejejmplo que te puede ayudar a entender por qué.
Supongamos que tenemos un campo de texto que contiene la fecha "May
25, 1996" y queremos cambiarlo a "June 25, 1996". Deberías selección
"May" y empezar a teclear "June". Tan pronto como teclearas la "J", el
campo no analizaría porque "J 25, 1996" no es un dato válido, aunque si
es un cambio válido. Hay un número de posibles soluciones para fechas y
otros tipos de datos cuando un cambio incompleto puede crear un
resultado no válido. Se puede cambiar la validación-por-pulsación para
que rechace definitivamente todos los cambios no válido (teclear "X" en
un campo de fecha, por ejemplo) pero permitir todos los cambios válidos
posibles. O cambiar a un campo validado-en-action.
Esta sección describe cómo se an alineado las etiquetas y los campos de texto del
ejemplo y requiere algún conocimiento de controladores de distribución.
Las líneas de parejas de etiquetas y campos de texto como los encontradas en la
calculadora de pagos son bastante comunes en los paneles que implementan
formularios. Aquí está el código que distribuye las etiquetas y los campos de texto.
. . .
//distribuye las etiquetas sobre el panel
JPanel labelPane = new JPanel();
labelPane.setLayout(new GridLayout(0, 1));
labelPane.add(amountLabel);
labelPane.add(rateLabel);
labelPane.add(numPeriodsLabel);
labelPane.add(paymentLabel);
setContentPane(contentPane);
. . .
Podrías haberte sorprendido de encontrar que las etiquetas fueran distribuidas sin
referencia a los campos de texto, y de hecho, están en un panel diferente, sólo
alineados correctamente con ellos. Esto es un efecto colateral de los controladores
de distribución usados por el programa.
Como muestra el diagrama, el progra usa dos controladores GridLayout, uno para
la columna de etiquetas y otro para la columna de campos de texto. GridLayout
garantiza que todos sus componentes sean del mismo tamaño, por eso todos los
campos de texto tienen la mista altura y todas las etiquetas tienen la misma altura.
Para conseguir que las etiquetas y los campos de texto esten alineados, el
programa usa un tercer controlador, un BorderLayout. con sólo dos componentes,
en la izquierda y en el centro, BorderLayout garantiza que las columnnas son de
la misma altura. Y así se alinean las etiquetas y los campos de texto.
Otra forma de conseguir alinear las etiquetas y los campos de texto es utilizar el
más complejo de los controladores de distribución del AWT, el GridBagLayout.
password.addActionListener(showSwingWorkerDialog);
Como con los campos de texto, el argumento pasado al constructor
JPasswordField indica que el campo deberá tener 10 columnas de ancho. Por
defecto, un campo password muestra asteriscos "*" por cada caracter tecleado. La
llamada a setEchoChar lo cambia por el signo de almohadilla "#". finalmente, el
código añade una oyente de action al campo password. El método
actionPerformed del oyente de actuib obtiene la password tecleada por el usuario
y la verifica con este código:
Esta tabla muestra los ejemplos que usan JTextField y dónde están descritos esos
esjemplos:
Ejemplo Dónde se Describe Notas
TextDemo.java Usa un text field con un oyent ede
Esta página
action.
TextFieldDemo.java Esta página Implementa dos campos
validados-por-pulsación.
Esta página y Usar
PasswordDemo.java la Clase Usa un campo de password.
SwingWorker
CustomDialog.java Incluye un campo de texto cuyo valor
Cómo crear Dialogs
es chequeado.
Swing
JTextPane
Lo primero que la mayoría d ela gente quiere saber es: ¿Qué diferencia hay entre
un editor pane y un text pane? Primer esta sección intenta responder esta
cuestión. Luego describe el código en el TextSamplerDemo específico de
JTextPane.
Cada uno de estos kits de editor ha sido registrado con el cla clase JEditorPane y
asociado con el formato de texto que el kit entiende. Cuando un fichero es cargado
dentro d eun editor pane, el panel chequea el formato del fichero con sus kits
registrados. Si se encuentra un kit registrado que soporta el formato del fichero, el
panel usa el kit para ller el fichero, mostrarlo y editarlo. Así, el editor pane se
convierte a sí mismo en un editor para ese formato de texto.
Podemos extender JEditorPane para soportar nuestro propio formato de texto
creando un editor kit para él, y luego usando registerEditorKitForContentType
de JEditorPane para asociarlo con nuestro formato de texto
Swing
Sumario de Texto
El API de texto de Swing es grande. Este tutorial ha mostrado un sencillo ejemplo
del uso de cada componente, cubriendo la línea de fundada por JTextComponent,
y muestra como utilizar esa herencia pra hacer cosas interesantes con los
componentes de texto.
El API de Texto
Esta tabla muestra los ejemplos que usan componentes de texto y dónde
encontrarlos.
Ejemplo Dónde se describe Notas
Esta página y
Usar Usa cada uno de los
TextSamplerDemo.java componentes de texto
Componentes
Swing.
de Texto Swing
Cómo usar Usa un campo de texto y
TextDemo.java
Text Field un área de texto básicos.
Proporciona un text pane
personalizado. Ilustra
TextComponentDemo.java Esta página muchas de las
características de los
componentes de texto.
Cómo usar Implementa dos campos
TextFieldDemo.java validados-por-pulsación
Text Fields
diferentes.
Cómo usar
Text Fields y
PasswordDemo.java Usa un campo password.
Usar la clase
SwingWorker
Cómo usar Pone un campo de texto
ToolBarDemo2.java en un barra de
Tool Bars
herrramientas.
Cómo usar Pone un campo de texto
CustomDialog.java
Dialogos validado en un diálogo.
Cómo usar Usa un editor pane para
TreeDemo.java mostrar ayuda cargada
Trees
desde un fichero HTML.
Swing
La mayoría del API que necesitas para usar tool tips está en JComponent,
y así lo heredan todos los componentes Swing (excepto los contenedores
de alto nivel). Este API se cubre en una tabla más adelante en esta
sección.
Más API de tool-tip se encuentra en clases individuales como
JTabbedPane. Cada página de componente tiene información sobre su
API de tool-tip, si existe.
Si quieres evitar o personalizar el manejo por defecto de tooltips,
probablemente tendrás que tratar directamente con JToolTip o
ToolTipManager
Como muestra la figura anterior, JTree muestra los datos verticalmente. Cada fila contiene
exactamente un ítem de datos (llamado un nodo). Cada árbol tiene un nodo raíz (llamado
Root en la figura anterior, del que descienden todos los nodos. Los nodos que no pueden
tener hijos se llaman nodos leaf (hoja). En la figura anterior, el aspecto-y-comportamiento
marca los nodos hojas con un círculo.
Los nodos que no sean hojas pueden tener cualquier número de hijos, o incluso no tenerlos.
En la figura anterior, el aspecto-y-comportamiento marca los nodos que no son hojas con un
carpeta. Normalmente el usuario puede expandir y contraer los nodos que no son hojas --
haciendo que sus hijos sena visibles o invisibles -- pulsando sobre él. Por defecto, los nodos
que no son honas empiezan contraidos.
Cuando se inicializa un árbo, se crea un ejemplar de TreeNode para cada nodo del árbol,
incluyendo el raíz. Cada nodo que no tenga hijos es una hoja. Para hacer que un nodo sin
hijos no sea una hoja, se llama al método setAllowsChildren(true) sobre él.
El resto de esta página explica los siguientes tópicos:
● Crear un árbol que reaccione a las selecciones
Aquí hay una imagen de una aplicación, en cuya mitad superior se muestra un
árbol en un scroll pane.
Intenta esto:
1. Compila y ejecuta la aplicación. El fichero fuente es TreeDemo.java.
2. Expande un nodo
Puedes hacer esto pulsando sobre el círculo que hay a la izquierda del ítem.
3. Selecciona un nodo.
Puedes hacer esto pulsando sobre el texto del nodo o el icono que hay justo a
la izquierda. El fichero mostrada en la parte inferior de la ventana muestra un
fichero que refleja el estado actual del nodo seleccionado.
public TreeDemo() {
...
//Crea los nodos.
DefaultMutableTreeNode top = new
DefaultMutableTreeNode("The Java Series");
createNodes(top);
//Tutorial
book = new DefaultMutableTreeNode(new BookInfo
("The Java Tutorial: Object-Oriented Programming for the Internet",
"tutorial.html"));
category.add(book);
...
category = new DefaultMutableTreeNode("Books for Java Implementers");
top.add(category);
//VM
book = new DefaultMutableTreeNode(new BookInfo
("The Java Virtual Machine Specification",
"vm.html"));
category.add(book);
//Language Spec
book = new DefaultMutableTreeNode(new BookInfo
("The Java Language Specification",
"jls.html"));
category.add(book);
}
Un árbol usa un unico renderizador para dibujar todos sus nodos. Por defecto, este
renderizador es un ejemplar de DefaultTreeCellRenderer.
La siguiente figura muestra una aplicación que nos permite añadir nodos al árbol de
forma dinámica. También podemos editar el texto de cada nodo.
button.setMargin(new Insets(0,0,0,0));
Problema: Los componentes de mu LayeredPane no se distribuyen correctamente.
De echo, aparecen inversas -- a menor profundidad menor componente.
● Esto puede sucedr si usas un int en lugar de un Integer cuando añades los
componentes al LayeredPane. Para ver que sucede, haz los siguientes
cambios a LayeredPaneDemo:
Cambia esto... por esto...
layeredPane.add(label, new Integer(i)); layeredPane.add(label, i);
Esta sección proporciona información útil para manejar todos los tipos de
eventos. Para reducir el código innecesario, puedes usar adaptadores y
clases internas para implementar los manejadores de eventos. Este
sección muestra cómo y cuándo hacerlo.
Esta es una imagen del GUI del applet. Para ejecutar el applet pulsa sobre
la imagen. El applet aparecerá en una nueva ventana del navegador.
Puedes encontrar el programa completo en Beeper.java. Aquí está el código que
implementa el manejo de eventos del botón:
Esta es una imagen del GUI del applet. Para ejecutar el applet
pulsa sobre la imagen. El applet aparecerá en una nueva
ventana del navegador.
Puedes encontrar el programa completo en MultiListener.java. Aquí sólo
tenemos el código que implementa el manejo de eventos de los botones:
button2.addActionListener(new Eavesdropper(bottomTextArea));
}
public void actionPerformed(ActionEvent e) {
topTextArea.append(e.getActionCommand() + newline);
}
}
Hasta ahora, la única clase de eventos que hemos visto son los eventos
action. Echemos un vistazo a un programa que maneja otros tipos de
eventos: eventos del ratón.
El siguiente applet muestra un área rectangular y un área de texto, cuando
ocurre un evento del ratón -- una pulsación, liberación, entrar o salir --
dentro del área rectangular (BlankArea) o su contenedor
(MouseEventDemo), el área de texto mostrará una cadena describiendo
el evento.
Esta es una imagen del GUI del applet. Para ejecutar el applet
pulsa sobre la imagen. El applet aparecerá en una nueva
ventana del navegador.
Puedes encontrar el programa completo en MouseEventDemo.java y
BlankArea.java. Aquí sólo tenemos el código que implementa el manejo
de eventos:
La clase AWTEvent
● addFocusListener
● addKeyListener
● addMouseListener
● addMouseMotionListener
/*
* An example of extending an adapter class instead of
* directly implementing a listener interface.
*/
public class MyClass extends MouseAdapter {
...
someObject.addMouseListener(this);
...
public void mouseClicked(MouseEvent e) {
...//Event handler implementation goes here...
}
}
¿Qué pasa si no queremos que nuestras clases de manejo de eventos
desciendan de una clase adaptador? Por ejemplo, supongamos que
escribimos un applet, y queremos que nuestra subclase Applet contenga
algún método para manejar eventos de ratón. Como el lenguaje Java no
permite la herencia múltiple, nuestra clase no puede descender de las
clases Applet y MouseAdapter. La solución es definir una clase interna
-- una clase dentro de nuestra subclase Applet -- que descienda de la
clase MouseAdapter,
Los eventos descritos en la tabla anterior pueden dividirse en dos grupos: eventos de
bajo nivel y eventos semánticos. Los eventos de bajo nivel representan las
ocurrencias del sistema windows o entradas de bajo nivel. Claramente, los eventos de
ratón y de tecla -- ambos como resultado de la entrada directa del usuario -- son
eventos de bajo nivel.
Los eventos component, container, focus, y window también son de bajo nivel. Los
eventos Component permite seguir los cambios en la posición, el tamaño y visibilidad
del componente. El evento Container permite conocer cuando se añade o elimina
cualquier componente a un contenedor particular. El evento Focus indica cuando un
componente gana o pierde el foco del teclado -- la habilidad de recibir caracteres
pulsados en el teclado. Los eventos windows nos informan del estado básico de
cualquier ventana, como un Dialog o un Frame.
Los eventos de ratón se dividen en dos grupos -- mouse motion y mouse -- por eso
un objeto puede escuchar eventos de mouse como las pulsaciones sin necesidad de
sobrecargar el sistema intentando conocer exactamente los movimientos del ratón, lo
que tiende a ocurrir frecuentemente.
Los eventos semánticos incluyen los eventos action, change, document, e item. Estos
eventos son el resultado de una interación específica del usuario con un componente
expecífico. Por ejemplo, un botón genera un evento action cuando el usuario lo pulsa,
y una lista genera un evento action cuando el usuario hace doble clicj sobre uno de
sus ítems. Cuando un usuarui selecciona un ítem de entre un grupo de ítems (como
una lista), se genera un evento item.
Swing
La clase ActionEvent
La clase CaretEvent
Aquí hay unos cuandos ficheros fuentes que también usan oyentes de
change:
● SliderDemo2.java
● ColorChooserDemo.java
● ColorChooserDemo2.java
La clase ChangeEvent
Esta es una imagen del GUI del applet. Para ejecutarlo, pulsa
sobre ella. El applet aparecerá en una nueva ventana de tu
navegador.
Prueba esto:
1. Pulsa el botón llamado "Start playing...".
La ventana se desplegará, generando uno o más eventos
component-shown y component-moved.
2. Pulsa el checkbox para ocultar la etiqueta.
La etiqueta genera un evento component-hidden.
3. Pulsa de nuevo el checkbox para mostrar la
etiqueta.
La etiqueta genera un evento component-shown.
4. Minimiza y maxima la ventana que contiene la
etiqueta.
No se obtienen eventos component-hidden ni
component-shown. Si queremos ser informados de los
eventos de iconificación deberíamos usar un oyente de
window.
5. Cambia el tamaño de la ventana que contiene la
etiqueta.
Veremos los eventos component-resized (y posiblemente)
de los cuatro componentes - etiqueta, checkbox, panel y
ventana. Si la controlador de distribución de la ventana y
el panel no hacen que cada componente sean tan anchos
como sea posible, el panel, la etiqueta y el checkbox
podrían no haber sido redimensionados.
La clase ComponentEvent
La clase ContainerEvent
La clase FocusEvent
Prueba esto:
1. Compila y ejecuta InternalFrameEventDemo. El fichero
fuente es InternalFrameEventDemo.java.
2. Despliega la ventana Evento Generator pulsando el botón
de la parte superior del applet.
Deberías ver un mensaje "Internal frame opened" en el
área de display.
3. Prueba varias cosas para ver que sucede. Por ejemplo,
pulsa el Event Generator para activarlo. Pulsa el Event
Watcher para desactivar el Event Generator. Pulsa la
decoración de la ventana Event Generator para
iconificara, maximizarla y cerrarla.
Puedes ver la página Cómo escribir un Oyente de Window
para más información sobre los tipos de eventos que
verás.
La clase InternalFrameEvent
● Converter.java
● CheckBoxDemo.java
● ComponentEventDemo.java
● PopupMenuDemo.java
● ScrollDemo.java
La clase ItemEvent
Para hacer que un componente obtenga el foco del teclado debemos seguir estos
pasos:
1. Asegurarnos de que el componente puede obtener el foco del teclado. Por
ejemplo, en algunos sistemas las etiquetas no pueden obtenerlo.
2. Asegurarnos de que el componente pide el foco en el momento apropiado.
Para componentes personalizados, probablemente necesitaremos implementar
un MouseListener que llame al método requestFocus cuandos e pulsa el
ratón.
3. Si estamos escribiendo un componente personalizado, implementaremos el
método isFocusTraversable del componente, para que devuelva true
cuando el componente está activado. esto permie al usuario usar Tab para ir a
nuestro componente.
Esta es una imagen del GUI del applet. Para ejecutarlo, pulsa sobre ella.
El applet aparecerá en una nueva ventana de tu navegador..
Prueba esto:
1. Pulsa sobre el campo de texto del applet para que obtenga el
foco.
2. Teclea una 'a' minúscula pulsando y liberando la tecla A del
teclado.
El campo de texto dispara tres eventos: un key-pressed, un
key-typed, y un key-released. Observa que el evento key-typed no
tiene información sobre el código de la tecla; los eventos key-typed
tampoco tienen información sobre los modificadores.
3. Pulsa el botón Clear.
Deberias hacer esto después de cada uno de los pasos siguientes.
4. Pulsa y libera la tecla Shift.
El campo de texto dispara dos eventos: un key pressed y un key
released. El campo de texto no genera ningún evento key-typed
porque Shift, por sí misma, no corresponde con ningún carácter.
5. Teclea una 'A' mayúscula pulsando las teclas Shift y A.
Verás los siguientes eventos, aunque quizás no en este orden: key
pressed (Shift), key pressed (A), key typed ('A'), key released (A),
key released (Shift).
6. Teclea una 'A' mayúsculas pulsando y liberando la tecla Caps
Lock, y luego pulsando la tecla A.
Deberías ver los siguientes eventos: key pressed (Caps Lock), key
pressed (A), key typed ('A'), key released (A). Observa que la tecla
Caps Lock no genera unevento key-released hasta que la pulses y
la liberes de neuvo. Lo mismo sucede para otras teclas de estado
como Scroll Lock y Num Lock.
7. Pulsa y mantén la tecla A..
¿Se repite automáticamente? Si es así, verás los mismos resultados
que verías si pulsaras y liberaras la tecla A repetidamente.
/** Handle the key pressed event from the text field. */
public void keyPressed(KeyEvent e) {
displayInfo(e, "KEY PRESSED: ");
}
/** Handle the key released event from the text field. */
public void keyReleased(KeyEvent e) {
displayInfo(e, "KEY RELEASED: ");
}
...
protected void displayInfo(KeyEvent e, String s){
...
char c = e.getKeyChar();
int keyCode = e.getKeyCode();
int modifiers = e.getModifiers();
...
tmpString = KeyEvent.getKeyModifiersText(modifiers);
La clase KeyEvent
Para detectar un evento list selection debemos registrar un oynete con el objeto
selection model apropiado. La clase JList también ofrece la opción de registrar un
oyente sobre la propia lista, mejor que directamente al selection model de la lista.
if (lsm.isSelectionEmpty()) {
output.append(" <none>");
} else {
// Find out which indexes are selected.
int minIndex = lsm.getMinSelectionIndex();
int maxIndex = lsm.getMaxSelectionIndex();
for (int i = minIndex; i <= maxIndex; i++) {
if (lsm.isSelectedIndex(i)) {
output.append(" " + i);
}
}
}
output.append(newline);
}
}
La clase ListSelectionEvent
Esto es una imagen del GUI del Applet. Para ejecutarlo, pulsa
sobre ella. El applet aparecerá en una nueva ventana de tu
navegador..
Prueba esto:
1. Mueve el cursor dentro del rectángulo amarillo de la
parte superior del applet.
Verás uno o más eventos mouse-entered.
2. Pulsa y mantén el botón del ratón..
Verás un evento mouse-pressed. Podrías ver algún evento
extra como un mouse-exited o mouse-entered.
3. Libera el botón del ratón.
Verás une vento mouse-released. Si no has movido el
ratón, seguirá un evento mouse-clicked.
4. Pulsa y mantén el botón del ratón, y arrástralo para el
cursor termine fuera del área del applet. Libera el
botón del ratón.
Verás un evento mouse-pressed, seguido de un evento
mouse-exited, seguido por un evento mouse-released. No
se ha notificado el movimiento del cursor. Para obtener
eventos mouse-motion, necesitamos implementar un
oyente de mouse-motion.
Puedes encontrar el código del applet en MouseEventDemo.java y
BlankArea.java. Aquí tenemos el código de manejo de eventos del
applet:
● GlassPaneDemo.java
● TableSorter.java
● AnimatorApplicationTimer.java
La Clase MouseEvent
void updateSize(MouseEvent e) {
int x = e.getX();
int y = e.getY();
currentRect.setSize(x - currentRect.x,
y - currentRect.y);
repaint();
}
}
La clase UndoableEditEvent
Otros uso común de los oyentes de window es parar los threads y liberar recursos cuando
una ventana es iconificada, y arracarlos otra vez cuando es desiconificada. De esta forma,
podemos evitarel uso innecesario del procesador o de otros recursos. Por ejemplo, cuando
una ventana que contiene una animación es iconificada, debería parar su thread de
animación para liberar cualquier buffer. Cuando la ventana es desiconificada se puede
arrancar el thread de nuevo y recrear los buffers.
Si queremos ser notificados cuando una ventana se hace visible o se oculta, deberíamos
registrar un oyente de component sobre la ventana.
El siguiente applet desmuestra los eventos windows. Pulsando el botón del applet,
podrás traer una pequeña ventana. La clase controladora escucha los eventos
window de la ventana, mostrando un mensaje siempre que detecte uno. Puedes
encontrar el código del applet en WindowEventDemo.java.
Esta es una imagen del GUI del applet. Para ejecutar el applet, pulsa sobre ella. El
applet aparecera en una nueva ventana del navegador..
Prueba esto:
1. Trae la ventana Window Demo pulsando el botón de la parte superior
del applet.
La primera vez que pulses este botón, verás un mensaje "Window opened" en
el área de display del applet.
2. Pulsa sobre la ventana si todavía no tiene el foco.
¿Ves un mensaje "Window activated" en el área de display del applet?
3. Iconiica la ventana, usando los controles de la propia ventana.
Verás un mensaje "Window iconified" en el área de display del applet.
4. Desiconifica la ventana.
Verás un mensaje "Window deiconified" en el área de display del applet.
5. Cierra la ventana, usando los controles de la ventana.
Verás "Window closing" en el área de display del applet. Como el manejador
de eventos llama a setVisible(false) en vez de dispose(), no verás
"Window closed".
La clase WindowEvent
Esta sección responde algunas de las preguntas más frecuentes sobre los
controladores de disposición:
● ¿Cómo puedo elegir un controlador de disposición?
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y
el applet aparecerá en una nueva ventana del navegador.
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y
el applet aparecerá en una nueva ventana del navegador.
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y
el applet aparecerá en una nueva ventana del navegador.
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y
el applet aparecerá en una nueva ventana del navegador.
* En el JDK 1.1 se introdujo un segundo inteface LayoutManager2. Este nuevo interface
extiende LayoutManager, proporcionando soporte para tamaño máximo y alineamiento.
Actualmente sólo BoxLayout implementa LayoutManager2. Todos los demás controladores de
distribución de la plataforma Java implementan sólo LayoutManager.
Swing
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador."
Como muestra el applet anterior, un BorderLayout tiene cinco áreas: north,
south, east, west, y center. Si agrandamos la ventana, el área central obtiene
tanto espacio disponible como le sea posible. Las otras áreas se extienden sólo lo
necesario para rellenar todo el espacio disponible.
El siguiente código crea el BorderLayout y los componentes que maneja. Aquí
está el programa completo. El programa funciona desde dentro d eun applet, con la
ayuda de AppletButton, o como una aplicación.
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet aparecerá
en una nueva ventana del navegador.
Creando uno o más contenedores de peso ligero que usen BoxLayout, podemos conseguir
distribuciones más complejas para las que normalmente se usaría GridBagLayout.
BoxLayout también es útil en algunas situaciones donde podríamos considerar la utilización de
GridLayout o BorderLayout. Hay una gran diferencia entre BoxLayout y los controladores
de distribución existentes en el AWT, y es que BoxLayout respeta el tamaño máximo y el
alineamiento X/Y de cada componente.
La siguiente figura muestra un GUI que usa dos ejemplares de BoxLayout. En la parte
superior del GUI un boxlayout de arriba-a-abajo situa una etiqueta sobre un scroll pane. En la
parte inferior del GUI, un boclayout de izquierda-a-derecha situa dos botones uno junto al otro.
Un BorderLayout combina las dos partes del GUI y se asegura que cualquier exceso de
espacio será entregado al scroll pane.
El siguiente código, tomado de ListDialog.java, disribuye el GUI. Este código está en el
constructor del diálogo, que está implementadocomo una subclase de JDialog. Las líneas en
negrita inicializan los boxlayout y les añaden los componentes.
Como alternativa al uso de componentes invisibles, algunas veces podemos usar bordes vacíos
para crear espacio alrededor de los componentes. Por ejemplo, el código anterior usa bordes
vacíos de 10 pixels entre todos los lados del dialog y sus contenidos, y entre las dos partes de
los contenidos. Los bordes son completamente independientes de los controladores de
distribución. Son sólo la forma en que los componentes Swing dibujan sus lados. Para más
información puedes ver Cómo usar Borders.
Características de BoxLayout
¿Qué pasa si ningún componente tiene una anchura máxima? Bien, si todos los
componentes tienen idéntico alineamiento X, todos los componentes serán tan
anchos como su contenedor. Si el alineamiento X es diferente, cualquier componente
con alineamiento 0.0 (izquierda) o 1.0 (derecha) serán más pequeños. Todos los
componentes con una alineamiento X intermedio (como el centro) serán tan anchos
como su contenedor. Aquí tenemos dos ejemplos:
Para conocer mejor BoxLayout, puedes hacer tus propios experimentos con
BoxLayoutDemo.
Prueba esto:
1. Compila y ejecuta BoxLayoutDemo. Los ficheros fuentes son
BoxLayoutDemo.java y BLDComponent.java.
2. Pulsa dentro de uno de los rectángulos
Así es como se cambia el alineamiento X de los rectángulos.
3. Pulsa el check box de la parte inferior de la ventana.
Esta desactiva las restriciones de tamaño de todos los rectángulos.
4. Agranda la ventana.
Esto hace que el contenedor de los rectángulos sea más grande que
la suma de los tamaño máximo preferidos de los rectángulos. El
contenedor en un JPanel que tiene un borde rojo, por lo que puedes
diferenciar donde están los laterales del contenedor.
glue
^
|
vertical Box.createVerticalGlue()
.
|
v
Box.Filler (segúns e
new Box.Filler(minSize, prefSize, maxSize)
personalizado especifique)
container.add(firstComponent);
container.add(Box.createRigidArea(new Dimension(5,0)));
container.add(secondComponent);
Nota: La clase Box proporciona otro tipo de relleno para poner espacio fijo
entre componentes: (struts) un puntal vertical u horizontal.
Desafortunadamente los puntales no tienen sus anchuras o alturas máximas
(para puntales horizontales o verticales, respectivamente). Esto significa que si
usamos un box horizontal dentro de un box vertical por ejemplo, el el box
horizontal puede algunas veces convertirse demasiado alto. Por esta razón,
recomendamos usar áreas rígidas en vez de "struts".
Glue
Se usa para especificar donde debería ir el exceso de espacio en la distribución.
Piensa en ello como un goma semi-humeda -- extrechable y expandible, que
sólo toma el espacio que los demás componentes no utilizan. Por ejemplo,
ponendo un glue horizontal entre dos componentes en un box de
izquierda-a-derecha, podemos hacer que todo el espacio extra se quede entre
los dos componentes en vez de a la derecha del contenedor. Aquí puedes ver un
ejemplo de ello:
container.add(firstComponent);
container.add(Box.createHorizontalGlue());
container.add(secondComponent);
container.add(firstComponent);
Dimension minSize = new Dimension(5, 100);
Dimension prefSize = new Dimension(5, 100);
Dimension maxSize = new Dimension(Short.MAX_VALUE, 100);
container.add(new Box.Filler(minSize, prefSize, maxSize));
container.add(secondComponent);
button1.setAlignmentY(Component.BOTTOM_ALIGNMENT);
button2.setAlignmentY(Component.BOTTOM_ALIGNMENT);
Como muestra la siguiente tabla, los botones, las etiquetas y los items de menú
Swing tienen diferentes valores de alineamiento X que todos los demás
componentes. De igual forma, los botones, los items de menú y las barras de
herraientas tienen diferentes alineamientis Y que todos los demás componentes.
Componente Swing Alineamiento X por defecto Alineamineto Y por defecto
Buttons, menu items LEFT_ALIGNMENT TOP_ALIGNMENT
Labels LEFT_ALIGNMENT CENTER_ALIGNMENT
Tool bars CENTER_ALIGNMENT TOP_ALIGNMENT
Todos los demás componentes
CENTER_ALIGNMENT CENTER_ALIGNMENT
Swing
El programa AlignmentDemo.java ofrece ejemplos de cómo corregir los problemas
de alineamientos. Normalmente es tan senciilo como forzar a los botones y las
etiquetas a que tengan alinamiento centrado. Por ejemplo:
label.setAlignmentX(Component.CENTER_ALIGNMENT);
...
button.setAlignmentY(Component.CENTER_ALIGNMENT);
comp.setBorder(BorderFactory.createCompoundBorder(
BorderFactory.createLineBorder(Color.red),
comp.getBorder()));
● Usar el viejo System.out.println para imprimir los tamaños mínimo, preferido
y máximo del componente y quizás sus límites.
El API de BoxLayout
Las siguiente tablas listan los métodos y constructores más usados de BoxLayout y
Box. El API para usar BoxLayut se divide en tres categorías:
● Crear objetos BoxLayout
● Crear rellenos
● Otros métodos útiles
Crear objetos BoxLayout
Método o Constructor Propósito
Crea un ejemplar de BoxLayout que controla el
Container especificado. El argumento entero
BoxLayout(Container, int) especifica si los componentes deberían distribuirse
de izquierda-a-derecha (BoxLayout.X_AXIS) o de
arriba-a-abajo (BoxLayout.Y_AXIS).
Crea un Box -- un contenedor de peso ligero que
usa BoxLayout con el alineamiento especificado
(BoxLayout.X_AXIS o BoxLayout.Y_AXIS).
Observa que un Box no es un JComponent -- está
implementado como una subclase de Container.
Box(int)
Esto hace que sea tan ligero como sea posible, pero
se pierde algunas características de JComponent
como los bordes. Si queremios un sencillo
JComponent como contenedor, debemos usar
JPanel.
Crea un Box que distribuye sus componentes de
static Box createHorizontalBox()
izquierda-a-derecha.
Crea un Box que distribuye sus componentes de
static Box createVerticalBox()
arriba-a-abajo.
Crear rellenos
Método o Constructor Propósito
Component createHorizontalGlue() Crea un componente de peso ligero
Component createVerticalGlue()
Component createGlue() glue.
Crea componente de peso ligero "strut"
Component createHorizontalStrut()
Component createVerticalStrut()
Nosotros recomendamos el uso de
áreas rígidas en vez de los struts.
Crea un componente de peso ligero con
los tamaños mínimo, preferido y
Box.Filler(Dimension, Dimension, Dimension) máximo especificados (con los
argumentos especificados en este
orden).
Otros métodos útiles
Método Propósito
Cambia los tamaños
mínimo, preferido u
void changeShape(Dimension, Dimension, Dimension) (en máximo del recipiente del
Box.Filler) objeto Box.Filler. La
distribución cambiara de
forma automática.
La siguiente tabla lista algunos de los muchos ejemplos que usan boxlayout:
Dónde se
Ejemplo Notas
describe
BoxWindow.java Usa un boxlayout para crear una
Esta página
columna de componentes centrados.
Demuestra como corregir los
problemas más comunes de
AlignmentDemo.java Esta página alineamiento. Usa dos ficheros de
imagen: images/middle.gif y
images/geek-cght.gif.
BoxLayoutDemo.java Nos permite jugar con los
Esta página
alineamientos y los tamaño máximos.
Un sencillo pero realista ejemplo que
ListDialog.java usa dos boxlayout uno de
Esta página
arriba-a-abajo y otro de
izquierda-a-derecha.
Cómo
escribir un Usa un boxlayout de arriba-a-abajo
InternalFrameEventDemo.java oyente de pra centrar botones y un scroll pane
Internal en un frame interno.
Frame
Swing
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
Como muestra el applet anterior, la clase CardLayout nos ayuda a manejar dos o
más componentes, (normalmente ejemplares de JPanel) que comparte el mismo
espacio. Otra forma de conseguir lo mismo es usar un JTabbedPane.
cards.add(BUTTONPANEL, p1);
cards.add(TEXTPANEL, p2);
Cuando se añaden componentes a un controlador que utiliza un CardLayout, se
debe utilizar la forma de dos argumentos del método add() de Container :
add(String name, Component comp). El primer argumento puede ser una
cadena con algo que identifique al componente que se está añadiendo.
Para elegir el componente mostrado por el CardLayout, se necesita algún código
adicional. Aquí puedes ver cómo lo hace el applet de esta página:
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
FlowLayout pone los componentes en un fila, domensionados a su tamaño
preferido. Si el espacio horizontal del contenedor es demasiado pequeño para
poner todos los componentes en un fila, FlowLayout usa múltiples filas. Dentro de
cada fila, los componentes están centrados (por defecto), alineados a la izquierda o
a la derecha como se especifica al crear el FlowLayout.
Abajo tenemos el código que crea el FlowLayout y los componentes que maneja.
(Aquí está el programa completo. El programa corre como un applet, con la ayuda
de AppletButton, o como una aplicación.)
public FlowLayout()
public FlowLayout(int alignment)
public FlowLayout(int alignment,
int horizontalGap, int verticalGap)
El argumento alignment debe tener el valor FlowLayout.LEFT,
FlowLayout.CENTER, o FlowLayout.LEFT. Los argumentos horizontalGap y
verticalGap especifican el número de pixels entre componentes. Si no
especificamos ningún valor, FlowLayout utiliza 5 como valor por defecto.
La siguiente tabla lista algunos de los ejemplos que usan flow layout.
Ejemplo Dónde se describe Notas
FlowWindow.java Esta página Inicializa un panel de contenido
para usar FlowLayout.
Cómo usar Usa el FlowLayout por defecto
ButtonDemo.java
Buttons para un JPanel.
Swing
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
Un GridLayout sitúa los componentes en una parrilla de celdas. Cada componente
toma todo el espacio disponible dentro de su celda, y cada celda es exactamente
del mismo tamaño. Si redimensionamos la ventana GridLayout, veremos que el
GridLayout cambia el tamaño de celda para todas sean lo más grande posible,
dando el espacio disponible al contenedor.
Abajo tenemos el código quecrea el GridLayout y los componentes que maneja.
(Aquí está el programa completo. El programa corre como un applet, con la ayuda
de AppletButton, o como una aplicación.)
contentPane.setLayout(new GridLayout(0,2));
La siguiente tabla lista algunos de los ejemplos que usan grid layout.
Ejemplo Dónde se describe Notas
GridWindow.java Esta página Usa una parrilla de dos
columnas
LabelDemo.java Cómo usar Labels Usa una parrilla de tres filas.
Anatomía de una Usa el constructor de
Converter.java Aplicación basada en GridLayout con cuatro
Swing argumentos.
Swing
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
GridBagLayout es el más flexible - y complejo - controlador de disposición
porpocionado por la platataforma Java. Como se ve en el applet anterior, un
GridBagLayout, sitúa los componentes en una parrilla de filas y columnas,
permitiendo que los componentes se espandan más de una fila o columna. No es
necesario que todas las filas tengan la misma altura, ni que las columnas tengan la
misma anchura. Esencialmente, GridBagLayout sitúa los componentes en celdas en
una parrilla, y luego utiliza los tamaños preferidos de los componentes que
detemina cómo debe ser el tamaño de la celda.
Especificar Restricciones
El ejemplo explicado
Esta es una imagen del GUI del applet, para ejecutarlo, pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
Abajo tienes el código que crea el GridBagLayout y los componentes que maneja.
Aquí tienes el programa completo. El programa puede ejecutarse dentro de un
applet, con la ayuda de AppletButton, o como una aplicación.
JButton button;
Container contentPane = getContentPane();
GridBagLayout gridbag = new GridBagLayout();
GridBagConstraints c = new GridBagConstraints();
contentPane.setLayout(gridbag);
c.fill = GridBagConstraints.HORIZONTAL;
c.ipady = 40;
Y antes de seleccionar las restricciones para el siguiente componente, el códio
reseta el valor de ipady al vaor por defecto
c.ipady = 0;
Para mayor claridad aquí tienes una tabla que muestra todas las obligaciones para
cada componente manejado por GridBagLayout. Los valores que no son por
defecto están marcados en negrita. Los valores que son diferentes de su entrada
anterior en la tabla están marcados en itálica.
Componente Restricciones
ipadx = 0
Todos los componentes
fill = GridBagConstraints.HORIZONTAL
ipady = 0
weightx = 0.5
weighty = 0.0
gridwidth = 1
Button 1
anchor = GridBagConstraints.CENTER
insets = new Insets(0,0,0,0)
gridx = 0
gridy = 0
weightx = 0.5
Button 2 gridx = 1
gridy = 0
weightx = 0.5
Button 3 gridx = 2
gridy = 0
ipady = 40
weightx = 0.0
Button 4 gridwidth = 3
gridx = 0
gridy = 1
ipady = 0
weightx = 0.0
weighty = 1.0
anchor = GridBagConstraints.SOUTH
Button 5
insets = new Insets(10,0,0,0)
gridwidth = 2
gridx = 1
gridy = 2
Todos los componentes de este contenedor son tan grandes como sea aposible,
dependiendo de su fila y columna. El programa consigue esto selección la variable
fill de GridBagConstraints a GridBagConstraints.HORIZONTAL, dejándola
seleccionada para todos los componentes. Si el programa no seleccionar el relleno,
los botones serían de su anchura natural, de esta forma:
Este programa tiene cuatro componentes que se espanden varias columnas
(buttons 4 y 5). Para hacer más alto el botón 4, le añadimos un borde interno
(ipady). Para poner espacio entre los botones 4 y 5, usamos insets para añadir un
mínimo de 10 pixels sobre el botón 5 y para que el botón 5 se situe en la parte
inferior de su celda.
Cuando se agranda la ventana del programa, la anchura de las columnas crece los
mismo que la ventana. Este es el resultado de cada componente de la primer fila
(donde cada componente tiene la anchura de una columna) tiene weightx = 1.0.
El valor real del weightx de estos componentes no tiene importancia. Lo que
importa es que todos los componentes (y así todas las columnas) tienen el mismo
peso que es mayor que cero. Si ningún componente manejado por el
GridBagLayout tuviera seleccionado weightx, cuando se ampliara la anchura del
contenedor, los componentes permanecerían juntos en el centro del contenedor de
sta forma:
Observamos que alargamos la ventana, la última fila es la que se hace más alta. Es
es así porque sólo el botón 5 tiene weighty mayor que cero.
Swing
● getLayoutAlignmentX(Container)
● getLayoutAlignmentY(Container)
● invalidateLayout(Container)
● maximumLayoutSize(Container)
Para más información sobre estos métodos, puedes ver LayoutManager2 API
documentation. También puedes ver el código fuente de BoxLayout, para ver
como implementa el interface LayoutManager2.
Cuando se implementa un controlador de distribución, podríamos queres usan un
objeto SizeRequirements para ayudarnos a determinar el tamaño y posición de
los componentes. Puedes ver el código fuente de BoxLayout para ver un ejemplo
de uso de SizeRequirements.
Aquí tienes el código fuente de DiagonalLayout, un controlador de distribución
personalizado que distribuye sus componentes diagonalmente, de izquierda a
derecha, con un componente por fila. Aquí tenemos a DiagonalLayout en acción:
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
Swing
Aquí tenemos un applet que muestra una ventana cuyo panel de contenido usa
posicionamiento absoluto
Esta es una imagen del GUI del Applet. Para ejecutarlo pulsa sobre ella y el applet
aparecerá en una nueva ventana del navegador.
Abajo podemos ver las declaraciones de las variables y la implementación del
constructor de la clase window. Aquí puedes ver el programa completo. El
programa se puede ejecutar como un applet, con la ayuda de AppletButton, o
como una aplicación.
public NoneWindow() {
Container contentPane = getContentPane();
contentPane.setLayout(null);
b1 = new JButton("one");
contentPane.add(b1);
b2 = new JButton("two");
contentPane.add(b2);
b3 = new JButton("three");
contentPane.add(b3);
Esta página ofrece una introducción al soporte de gráficos del AWT, con
enlaces a las páginas donde puedes encontrar más información.
Usar Imágenes
Realizar Animación
El objeto Graphics
El sistema de Coordenadas
Dibujar Formas
Dibujar Formas
La clase Graphics define métodos para dibujar los siguientes tipos de formas:
● Líneas (drawLine(), que dibuja una línea en el color actual del objeto Graphics, que es
inicializado con el color de primer plano del Componente)
● Rectángulos (drawRect(), fillRect(), y clearRect() -- donde fillRect() rellena un
rectángulo con el color actual del objeto Graphics, y clearRect() rellena un rectángulo con el
color de fondo del Componente)
● Rectángulos en 3 dimensiones (draw3DRect() y fill3DRect())
● Rectángulos con los bordes redondeados (drawRoundRect() y fillRoundRect())
● Ovalos (drawOval() y fillOval())
● Arcos (drawArc() y fillArc())
● Polígonos (drawPolygon() y fillPolygon())
Excepto para los polígonos y las líneas todas las formas son especificas utilizando su rectángulo
exterior. Una vez que hayas comprendido el dibujo de rectángulos, las otras formas son
relativamente sencillas. Por esta razón, esta página se concentra en el dibujo de rectángulos.
Aquí tienes un applet que podrías utilizar para implementar la selección básica en un
programa de dibujo. Cuando el usuario mantiene pulsado el botón del ratón, el applet
muestra continuamente un rectángulo. El rectángulo empieza en la posición del cursor
cuando el usuario pulsó el botón del ratón por primera vez y termina en la posición
actual del cursor.
A menos que la fuente por defecto de su visualizador de applets sea muy pequeña, el
texto mostrado en el applet anterior podría parecer demasiado grande en ocasiones. La
palabras podrían dibujarse unas sobre otras. Y como este applet no utiliza el método
insets() para proteger sus límites el texto podría dibujarse sobre el marco alrededor
del applet. La siguiente página amplía este ejemplo, enseñándolo como hacer que el
texto quepa en un espacio dado.
Aquí sólo está el código que dibuja las formas geométricas. Las variables rectHeight y
rectWidth especifican el tamaño en pixels del área en la que debe dibujarse cada
forma. Las variables x e y se cambian para cada forma, para que no se dibujen unas
encimas de las otras.
Color bg = getBackground();
Color fg = getForeground();
. . .
// drawLine()
g.drawLine(x, y+rectHeight-1, x + rectWidth, y); // x1, y1, x2, y2
. . .
// drawRect()
g.drawRect(x, y, rectWidth, rectHeight); // x, y, width, height
. . .
// draw3DRect()
g.setColor(bg);
g.draw3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
. . .
// drawRoundRect()
g.drawRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch
. . .
// drawOval()
g.drawOval(x, y, rectWidth, rectHeight); // x, y, w, h
. . .
// drawArc()
g.drawArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h
. . .
// drawPolygon()
Polygon polygon = new Polygon();
polygon.addPoint(x, y);
polygon.addPoint(x+rectWidth, y+rectHeight);
polygon.addPoint(x, y+rectHeight);
polygon.addPoint(x+rectWidth, y);
//polygon.addPoint(x, y); //don't complete; fill will, draw won't
g.drawPolygon(polygon);
. . .
// fillRect()
g.fillRect(x, y, rectWidth, rectHeight); // x, y, width, height
. . .
// fill3DRect()
g.setColor(bg);
g.fill3DRect(x, y, rectWidth, rectHeight, true);
g.setColor(fg);
. . .
// fillRoundRect()
g.fillRoundRect(x, y, rectWidth, rectHeight, 10, 10); // x, y, w, h, arcw, arch
. . .
// fillOval()
g.fillOval(x, y, rectWidth, rectHeight); // x, y, w, h
. . .
// fillArc()
g.fillArc(x, y, rectWidth, rectHeight, 90, 135); // x, y, w, h
. . .
// fillPolygon()
Polygon filledPolygon = new Polygon();
filledPolygon.addPoint(x, y);
filledPolygon.addPoint(x+rectWidth, y+rectHeight);
filledPolygon.addPoint(x, y+rectHeight);
filledPolygon.addPoint(x+rectWidth, y);
//filledPolygon.addPoint(x, y);
g.fillPolygon(filledPolygon);
Swing
Dibujar Texto
Aquí hay un applet que ilustra lo que puede suceder cuando no se tiene
cuidado con el posicionamiento del texto:
Nota: Como algunos viejos navegadores no soportan 1,1, el
applet anterior es una versión 1.0, (aquí está código 1.0; y
aquí está el codigo 1.1). Para ejecutar la versión 1.1 del
applet, puedes ir a example-1dot1/TextXYDemo.html.
Para más información sobre la ejecución de applets puedes ver
Sobre Nuestros Ejemplos.
while (!fontFits) {
if ( (fontMetrics.getHeight() <= maxCharHeight)
&& (fontMetrics.stringWidth(longString)
<= xSpace)) {
fontFits = true;
} else {
if (size <= minFontSize) {
fontFits = true;
} else {
g.setFont(font = new Font(name,
style,
--size));
fontMetrics = g.getFontMetrics();
}
}
}
El ejemplo de código anterior utiliza los métodos getFont(), setFont(),
y getFontMetrics() de la clase Graphics para obtener y seleccionar la
fuente actual y para obtener el objeto FontMetrics que corresponde con
el font. Desde los métodosgetHeight() y getStringWidth() de
FontMetrics, el código obtiene la información sobre el tamaño vertical y
horizontal de la fuente.
La siguiente figura muestra parte de la información que un objeto
FontMetrics puede proporcionar sobre el tamaño de una fuente.
Aquí tienes un sumario de los métodos de FontMetrics que devuelven
información sobre el tamaño vertical de la fuente:
getAscent(), getMaxAscent()
El método getAscent() devuelve el número de pixels entre la línea
de ascendetes y la línea base. Generalmente, la línea de
ascendentes representa la altura típica de una letra mayúscula.
Especificamente, los valores ascendente y descendente los elige el
diseñador de la fuente para representar el "color" correcto del
texto, o la densidad de la tinta, para que el texto aparezca como lo
planeó el diseñador. El ascendente típico porporciona suficiente
espacio para casi todos los caracteres de la fuente, excepto quizás
para los acentos de las letras mayúsculas. El método
getMaxAscent() tiene en cuenta estos caracteres
excepcionalmente altos.
getDescent(), getMaxDescent()
El método getDescent() devuelve el número de pixels entre la
línea base y la línea de descendentes. En la mayoría de las fuentes,
todos los caracteres caen en la línea descendente en su punto más
bajo. Sólo en algunos caso, podrá utilizar el método
getMaxDescent() para obtener una distancia garantizada para
todos los caracteres.
getHeight()
Obtiene el número de pixels que se encuentran normalmente entre
la línea base de una línea de texto y la línea base de la siguiente
línea de texto. Observa que esto incluye el espacio para los
ascendentes y descendentes.
getLeading()
Devuelve la distancia sugerida (en pixels) entre una línea de texto y
la siguiente. Especificamente, esta es la distancia entre la línea
descendente de una línea de texto y la línea ascendente de la
siguiente.
Observa que el tamaño de la fuente (devuelto por el método getSize()
de la clase Font) es una media abstracta. Teoricamente, corresponde al
ascendente más el descendente. Sin embargo, en la práctica, el
diseñador decide la altura que debe tener una fuente de "12 puntos". Por
ejemplo, Times de 12-puntos es ligeramente más baja que Helvetica de
12-puntos. Típicamente, las fuentes se miden en puntos, que es
aproximadamente 1/72 de pulgada.
La siguiente lista muestra los métodos que proporciona FontMetrics para
devolver información sobre el tamaño horizontal de una fuente. Estos
métodos tienen en cuenta el espacio entre los caracteres. Más
precisamente, cada método no devuelve el número de pixels de un
carácter particular (o caracteres), sino el número de pixels que avanzará
la posición actual cuando se muestre el carácter (o caracteres).
Llamamos a esto anchura de avance para distinguirla de la anchura del
texto.
getMaxAdvance()
La anchura de avance (en pixels) del carácter más ancho de la
fuente.
bytesWidth(byte[], int, int)
La anchura de avance del texto representado por el array de bytes
especificado. El primer argumento entero especifica el origen de los
datos dentro del array. El segundo argumento entero especifica el
número máximo de bytes a chequear.
charWidth(int),charWidth(char)
La anchura de avance del carácter especificado.
charsWidth(char[], int, int)
La anchura de avance de la cadena representada por el array de
caracteres especificado.
stringWidth(String)
La anchura de avance de la cadena especificada.
getWidths()
La anchura de avance de cada uno de los primeros 256 caracteres
de la fuente.
Swing
Utilizar Imágenes
Esto es una imagen:
Cargar Imágenes
Mostrar Imágenes
g.drawImage(myImage, 0, 0, this);
Esta sección explica las cuatro formas de drawImage(), dos de la
cuales escalan la imagen. Al igual que getImage(), drawImage() es
asíncrona, vuelve inmediatamente incluso si la imagen no se ha cargado
o dibujado completamente todavía.
Manipular Imágenes
Cargar Imágenes
Esta página describe cómo obtener el objeto Image correspondiente a una imagen. Siempre
que la imagen este en formato GIF o JEPG y se conozca su nombre de fichero o su URL, es
sencillo obtener un objeto Image para ella: con solo utilizar uno de los métodos getImage()
de Applet o Toolkit. Los métodos getImage() vuelven inmediatamente, sin comprobar si
existen los datos de la imagen. Normalmente la carga real de la imagen no empieza hasta que
el programa intenta dibujarla por primera vez.
Para muchos programas, esta carga en segundo plano funciona bien. Otros, sin embargo,
necesitan seguir el proceso de carga de la imagen. Esta página explica cómo hacerlo utilizando
la clase MediaTracker y el interface ImageObserver.
Finalmente, esta página contará cómo crear imágenes al vuelo, utilizando una clase como
MemoryImageSource.
Esta sección explica primero los métodos getImage() de la clase Applet y luego los
de la clase Toolkit.
Las clase Applet suministra dos métodos getImage():
● public Image getImage(URL url)
Sólo los applets pueden utilizar los métodos getImage() de la clase Applet.
Además, los métodos getImage() de Applet no trabajan hasta que el applet tenga
un contexto completo (AppletContext). Por esta razón, estos métodos no trabajan si
se llaman desde un constructor o en una sentencia que declara una variable de
ejemplar. En su lugar, debería llamar a getImage() desde un método como init().
El siguiente ejemplo de código muestra cómo utilizar los métodos getImage() de la
clase Applet. Puede ver Crear un GUI para una explicación de los métodos
getCodeBase() y getDocumentBase().
int w = 100;
int h = 100;
int[] pix = new int[w * h];
int index = 0;
for (int y = 0; y < h; y++) {
int red = (y * 255) / (h - 1);
for (int x = 0; x < w; x++) {
int blue = (x * 255) / (w - 1);
pix[index++] = (255 << 24) | (red << 16) | blue;
}
}
Image img = createImage(new MemoryImageSource(w, h, pix, 0, w));
Swing
Dibujar Imágenes
Aquí tienes un ejemplo de código que muestra una image a su tamaño normal en
la esquina superior izquierda del área del Componente (0,0):
g.drawImage(image, 0, 0, this);
Aquí tienes un ejemplo de código que muestra una imagen escalada para tener 300
pixels de ancho y 62 de alto, empezando en las coordenadas (90,0):
Realizar Animación
Lo que todas las formas de animación tienen en común es que todas ella crean
alguna clase de percepción de movimiento, mostrando marcos sucesivos a una
velocidad relativamente alta. La animación por ordenador normalmente muestra
10-20 marcos por segundo. En comparación, la animación de dibujos manuales
utiliza desde 8 marcos por segundo (para una animación de poca calidad) hasta 24
marcos por segundo (para movimiento realista) pasando por 12 marcos por
segundo (de la animación estandard). Las siguientes páginas cuentan todo lo que
se necesita saber para escribir un programa Java que realice una animación.
Antes de empezar: Comprueba las herramientas de animación existentes y los
applet como Animator, para ver si puedes utilizar uno de ellos en vez de escribir su
propio programa.
Generar Gráficos
Eliminar el Parpadeo
Esta sección enseña cómo realizar una animación clásica, al estilo de los
dibujos animados, dando una secuencia de imágenes.
El Bucle de Animación
//Display it.
repaint();
Comportamiento Educado
Dos caracteristicas más de estas plantillas de animación pertenecen a la
categoría de comportamiento educado.
La primera caracteristica es permitir explicitamente que el usuario pare (y
arranque) la animación, mientras el applet o la aplicación sean visibles. La
animación puede distraer bastante y es buena idea darle al usuario el poder
de pararla para que pueda concentrarse en otra cosa. Esta caracteristica
está implementada sobreescribiendo el método mouseDown() para que
pare o arranque el thread de la animación., dependiendo del estado actual
del thread. Aquí tiene el código que implementa esto:
. . .
Animar Gráficos
Esta página genera un applet ejemplo que crea un efecto de movimiento,
dibujando cuadrados alternativos. Los cuadrados son dibujados por el método
fillRect() de Graphics. Aquí tienes el applet en acción:
starfield.gif:
//If we have a valid width and height for the background image,
//draw it.
w = stars.getWidth(this);
h = stars.getHeight(this);
if ((w > 0) && (h > 0)) {
g.drawImage(stars, (d.width - w)/2,
(d.height - h)/2, this);
}
//If we have a valid width and height for the background image,
//draw it.
w = rocket.getWidth(this);
h = rocket.getHeight(this);
if ((w > 0) && (h > 0)) {
g.drawImage(rocket, ((frameNumber*5) % (w + d.width)) - w,
(d.height - h)/2, this);
}
}
Se podría pensar que este programa no necesita limpiar el fondo ya que utiliza una
imagen de fondo. Sin embargo, todavía es necesario limpiar el fondo. Una razón es
que el applet normalmente empieza a dibujar antes de que las imágenes estén
cargadas totalmente. Si la imagen del cohete se cargara antes que la imagen de
fondo, vería partes de varios cohetes hasta que la imagen de fondo sea cargada.
Otra razón es que si el área de dibujo del applet fuera más ancha que la imagen de
fondo, por alguna razón, vería varios cohetes a ambos lados de la imagen de
fondo.
Se podría resolver este problema retardando todo el dibujo hasta que las dos
imágenes estuvieran totalmente cargadas. El segundo problema se podría resolver
escalando la imagen de fondo para que cubriera todo el área del applet. Aprenderá
como esperar a que las imágenes se carguen completamente en Aumentar el
Rendimiento y la Apariencia de una Animación, más adelante en esta lección. El
escalado se describe en Mostrar Imágenes.
Swing
T9.gif: T10.gif:
Aquí está el applet en acción. Recuerda que puedes pulsar sobre el applet para
parar y arrancar la animación.
El código de este ejemplo es incluso más sencillo que el del ejemplo anterior, que
movía una imagen. Aquí está el código que difiere del ejemplo que movía una
imagen:
Los bordes son muy utilizados para dibujar líneas, títulos y espacios
vacíos alrededor de los componentes. (Podrías haber notado que los
ejemplos de esta sección usan muchos bordes). Esta página explicará
como añadir un borde a cualquier componente JComponent.
Aquí hay un ejemplo de uso de un Action para crear un botón de una barra de
herramientas y un ítem de menú que realizan la misma función:
Aquí está lo que ve el usuario cuando la acción "Go left" está desactivada:
button = toolBar.add(leftAction);
button.setText(""); //an icon-only button
button.setToolTipText("This is the left button");
menuItem = mainMenu.add(leftAction);
menuItem.setIcon(null); //arbitrarily chose not to use icon in menu
El API de Action
Las siguientes tablas listan los métodos y constructores más usados de Action. El
API para usar objetos Action se divide en dos categorías:
● Crear y usar un Action
Aquí tenemos un applet que usa iconos para dos propósitos diferentes:
Está es una imagen del GUI del Applet, para ejecutarlo, pulsa sobre ella. El
applet aparecerá en una nueva ventana del navegador.
Un icono en una etiqueta impelementa el área fotgráfica del applet. El applet tambíen
usa iconos para decorar los botones Previous Picture y Next Picture de la parte
inferior de la ventana del applet.
Prueba esto:
1. Ejecuta el applet.
El applet anterior se ejecuta usando Java Plug-in. Si lo prefieres,
puedes ejecutarlo con un navegador o Applet Viewer que soporte JDK
1.1 y Swing. Aquí está el fichero que contiene la etiqueta <APPLET>
para ejecutar el applet IconDemoApplet.java. Para más información
sobre la ejecución de applets, puedes ver Eejcutar Applets Swing.
2. Pulsa los botones Previous Picture y Next Picture, para ver las
fotos.
3. Mantén el cursor sobre una foto. Un tool-tip indicará el nombre de la
foto actual y su anchura y altura.
4. PAra ver tus propias fotos, modifica los parámetros del applet.
Necesitarás proporcionar, el nombre, la anchura y la altura para cada
foto. Durante la inicialización, el applet lee sus parámetros y almacena
la informaicón en un vector de objetos Photo.
//create the image icons for the next and previous buttons
ImageIcon nextIcon = new ImageIcon(getURL("images/LEFT.gif"));
ImageIcon previousIcon = new ImageIcon(getURL("images/left.gif"));
...
//use them to create a buttons
previous = new JButton("Previous Picture", previousIcon);
...
next = new JButton("Next Picture", nextIcon);
El único argumentos para el constructor del icono es la URL del fichero que contiene la
imagen. El método getURL añade el code base del applet al nombre del fichero que
contiene la imagen del applet. Puedes copiar este método para usarlo en tus applets.
try {
url = new URL(codeBase, filename);
} catch (java.net.MalformedURLException e) {
System.out.println("Couldn't create image: badly specified URL");
return null;
}
return url;
}
La clase ImageIcon proporciona otros muchos constructores para crear iconos desde
un array de bytes, una imagen o desde un nombre de fichero.
Ahora veamos el código que carga las fotografías:
El API de Icon
La siguiente tabla lista unos pocos de los muchos ejemplos que usan
ImageIcon.
Dónde se
Ejemplo Notas
describe
Un applet que usa una
etiqueta para mostrar
IconDemoApplet.java Esta
imagenes grandes y dos
página.
botones que tienen tanto
imagenes como texto.
Cómo usar Muestra como usar Iconos
ButtonDemo.java en los botones de una
Buttons
aplicación.
Cómo usar
CheckBoxDemo.java Check Usa múltiplés imágenes
JPEG.
Boxes
Demustra el uso de iconos
Cómo usar en las etiquetas de una
LabelDemo.java
Labels aplicación, con y sin texto
de acompañamiento.
Cómo Muestra como usar Iconos
DialogDemo.java,
hacer estándard en los cuadros
CustomDialog.java,
Dialogs de diálogo.
Cómo usar Muestra como cambiar los
TreeIconDemo.java iconos mostrados en los
Trees
nodos de un árbol.
Muestra cómo especificar
Cómo usar el icono de una botón de
ActionDemo.java una barra de herramientas
Actions
o un ítem de menú usando
un Action.
Swing
UIManager.setLookAndFeel(
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel");
Aquí podemos ver algunos de los argumentos que podemos usar con
setLookAndFeel:
UIManager.getCrossPlatformLookAndFeelClassName()
Devuelve el string para uno de los aspecto-y-comportamiento
garantizados que funciona -- el aspecto y comportamiento Java.
UIManager.getSystemLookAndFeelClassName()
Especifica el aspecto y comportamiento de la plataforma actual. En
plataformas Win32, esto especifica el aspecto y comportamiento
Windows. En plataforma Mac OS , esto especifica el aspecto y
comportamiento Mac OS. En plataformas Sun, especifica el aspecto y
comportamiento CDE/Motif.
"javax.swing.plaf.metal.MetalLookAndFeel"
Especifica el aspecto y comportamiento Java. (El nombre código para
este aspecto y comportamiento era Metal.) Este string es el valor
devuelto por el método
getCrossPlatformLookAndFeelClassName.
"com.sun.java.swing.plaf.windows.WindowsLookAndFeel"
Especifica el aspecto y comportamiento Windows. Actualmente, sólo
podemos usar este aspecto y comportamiento en systemas Win32.
"com.sun.java.swing.plaf.motif.MotifLookAndFeel"
Especifica el aspecto y comportamiento CDE/Motif. Este puede ser
utilizado sobre cualquier plataforma.
"javax.swing.plaf.mac.MacLookAndFeel"
Especifica el aspecto y comportamiento Mac OS. En el momento de
crear este tutor, este aspecto y comportamiento estába en fase bera
y no está disponible como parte del JFC 1.1 o JDK 1.2. en su lugar,
puedes descargarlo, siguiendo las instrucciones de la JFC Home Page.
Aquí están los pasos que sigue el controlador del UI para determinar el
aspecto y comportamiento cuando se inicializa a sí mismo:
1. Si el programa selecciona el aspecto y comportamiento antes de
crear ningún componente, el UI trata de crear un ejemplar de la
clase especificada. Si tiene éxito, todos los componentes usarán ese
aspecto y comportamiento.
2. Si el programa no ha tenido éxito con el aspecto y comportamiento
especificado, antes de crear el primer componente, el UI comprueba
si el usuario ha especificado uno en un fichero llamado
swing.properties. Busca el fichero en el directorio lib de la versión
de Java. Por ejemplo, si estamos usando el intérprete Java en
javaHomeDirectory\bin, entonces el fichero swing.properties (si
existe) está en javaHomeDirectory\lib. Si el usuario ha
especificado un aspecto y comportamiento, de nuevo el UI intenta
ejemplarizar la clase especificada. Aquó hay un ejemplo de los
contenidos de un fichero swing.properties:
# Swing properties
swing.defaultlaf=com.sun.java.swing.plaf.motif.MotifLookAndFeel
3. Si ni el programa ni el usuario han especificado un aspecto y
comportamiento adecuados, el programa usar el aspecto y
comportamiento Java.
UIManager.setLookAndFeel(lnfName);
SwingUtilities.updateComponentTreeUI(frame);
frame.pack();
Swing
Prueba esto:
1. Compila y ejecuta la aplicación. El fichero principal es
ProgressBarDemo.java.
2. Pulsa el botón Start. Mira la barra de progreso mientras la tarea se
completa.
Una vez que la tarea ha empezado, el temporizador hace que la barra de progreso se
actualice cada segundo hasta que la tarea se haya completado. Aquí está códio de
ProgressBarDemo.java que crea el temporizador y, cuando el usario pulsa el botón
Start, lo arranca:
public AnimatorApplicationTimer(...) {
...
// Set up a timer that calls this
// object's action handler.
timer = new Timer(delay, this);
timer.setInitialDelay(0);
timer.setCoalesce(true);
...
}
//Display it.
repaint();
}
...
}
Puedes encontrar el programa completo en
AnimatorApplicationTimer.java.
El API de Timer
● Ejecutar el Timer
● Escuchar el Disparo del Timer
Ajuste fino de la Operación del Timer
Método o Constructor Propósito
Crea un timer inicializado con un retardo y un
Timer(int, ActionListener)
oyente. Este es el único constructor de Timer.
void setDelay(int)
int getDelay() Selecciona u obtiene el retardo entre disparos.
void setInitialDelay(int) Selecciona u obtiene el retardo para el disparo
int getInitialDelay() inicial.
void setRepeats(boolean)
boolean isRepeats() Selecciona u obtiene si el timer se repite.
void setCoalesce(boolean) Selecciona u obtiene su el timer junta varios
boolean isCoalesce() disparos pendientes en un único disparo.
Ejecutar el Timer
Método Propósito
void start() Activa el timer. restart cancela cualquier disparo
void restart() pendiente.
void stop() Desactiva el timer.
boolean isRunning() Obtiene si el timer se está ejecutando.
Esta tabla meustra algunos de los ejemplos que usan Timer y dónde se
describen.
Ejemplo Dónde se describe
ProgressBarDemo.java Esta página y Cómo usar Monitor Progress
AnimatorApplicationTimer.java Esta página.
SliderDemo.java Cómo usar Sliders
Swing
Convertir a Swing
Esta lección trata sobre por qué y cómo convertir nuestros programas basados en
el AWT 1.1 para usar componentes Swing.
Recursos de Conversión
Por lo que la pregunta sería ahora "¿Por qué no debo convertir a Swing?"
Es razonable posponer la conversión si pensamos que nuestros usuarios no podrán
ejecutar los programas Swing de forma conveniente. Por ejemplo, su nuestro
programa es un applet y queremos que todo el mundo pueda usarlo en internet,
deberíamos considerar cuandos navegantes del Web tienen navegadores que
puedan ejecutar programas Swing. En el momento de escribir esto, la mayoría de
los navegadores no tienen soporte Swing interno; los usuarios deben añadirlo
descargando e instalando Java Plug-in.
Tienes la ipción de actualizarte a Java 2 (JDK 1.2) cuando conviertas a Swing. Sin
embargo, no necesitas decidirlo ahora. Los programas escritos en JDK 1.1 y Swing
funcionan muy bien en Java 2.
Swing
Necesitares una copia de todos los ficheros del programa, incluyendo los ficheros .java y
.class. Necesitamos estas copias por varias razones:
● Cualquier usuario que no pueda ejecutar programas Swing necesitará ejecutar el viejo
programa AWT.
● Necesitaremos referirinos al código fuente durante el proceso de conversión.
● Después de la conversión, deberemos ejecutar las dos versiones del programa para
compararlos.
● Después de la conversión, podemos comparar el código fuente de ambas versiones para
aplicar lo que hemos aprendido en otros programas que necesitemos convertir.
Este paso pone el compilador a trabajar por nosotros. Es útil eliminar todas las importaciones
del AWT incluso si nuestro programa todavía utiliza clases AWT -- como sus controladores de
distribución -- porque, sin estas sentencias, el compilador generará erroees "not found" por
cada componente AWT usado en nuestro programa y el número de línea donde es utilizado.
Esto ayuda a localizar cada uno de los componentes AWT usado por nuestro programa para
que podamos reemplazarlos por su equivalente Swing en el Paso 8, luego añadiremos las
importaciones para las clases AWT que realmente necesitemos.
import java.applet.Applet;
o
import java.applet.*;
import javax.swing.*;
Esto importa todos los componentes Swing además de algunas otras clases Swing. Si
queremos podemos ser más meticulosos y añadir una sentencia import por cada clase Swing
que utilicemos.
Paso 6: Cambiar cada componente AWT por su equivalente Swing más cercano.
Button button = new Button("A Button"); JButton button = new JButton("A Button");
button.addActionListener(this); button.addActionListener(this);
Estaras contento de aprender que un gran número de componentes Swing tiene el código
compatible con su pareja AWT.
En el lado contrario tenemos que no todos los componentes Swing son totalmente
compatibles con los componentes AWT. Por eso, para algunos componentes AWT tendremos
que re-escribir algún código cuando lo reemplazemos por un componente Swing. Además,
podríamos elegir hacer cambios innecesarios para aprovecharnos de las características
Swing. Por ejemplo, podríamos querer añadir una imagen a un botón, podríamos querer
soportar la accesibilidad llamando al método setLabelFor sobre las etiquetas asociadas con
otros componentes. Recursos de Conversión tiene más información para ayudarnos con las
conversiones que requieren algo más que un simple cambio de nombre y sobre las
conversiones opcionales.
Habrás notado que el código Swing de la segunda fila llama a getContentPane múltiples
veces, lo que es ineficiente si nuestro programa usa muchos componentes. El código Swing
de la tercera fila mejora el código, obteniendo el panel de contenido una sóla vez,
almacenándolo en una variable, y usando la variable para añadir componentes y seleccionar
el controlador de distribución.
Una vez modificado el código fuente como se ha indicado en los pasos anteriores,
utilizaremos el compilador para intentar compilar nuestro programa.
javac MyClass.java
Durante este paso, el compilador nos está ayudando a identificar cualquier conversión que
nos haya pasado por alto. No podemos esperar que el programa se compile a la primera.
El compilador puede ayudarnos:
● Encontrando cada componente AWT que nos hayamos olvidado de convertir a su
equivalente Swing. Si seguimos el paso 2 el compilador mostrará un mensaje de error
como este por cada componente AWT que quede en nuestro programa.
Probablemente querramos que los programas sean similares, estén abiertos a las mejoras
ofrecidas por swing y cualquier diferencia inherente en los dos GUIs.
Ahora es el momento de limpiar nuestro código. Si hemos dejado algún código para corregir
alguna deficiencia o bug del AWT , es el momento de limpiarlo!
Swing
Recursos de Conversión
Te proporcionamos estos recursos para ayudarte a convertir tus programas a
Swing:
¿En qué se diferencias los Componentes Swing de los del AWT?
Si no has leído esta página, considera leerla ahora. Proporciona una base útil
para la perspectiva del proceso de conversión.
Reemplazos Swing para Componentes AWT
Lista cada uno de los componentes AWT y su reemplazo Swing, y contiene
notas que pueden ayudarnos con los cambios más sencillos que tendríamos
que hacer en nuestro código. Además, la tabla apunta cuando podríamos
querer actualizar a un componente Swing más potente. Por ejemplo,
podríamos querer reemplazar un componente de texto AWT con un campo
password de Swing en vex de un campo de texto normal.
Trucos de Conversión General
Proporciona información sobre los problemas de conversión generales como la
seguridad con los threads, dibujo, etc.
Trucos de Conversión Específicos de Componentes
Proporciona detalles sobre la conversión específica de algunos componentes,
como las áreas de texto, que tienden a requerir más trabajo para convertirla.
Proporciona pequeños ejemplos donde sea apropiado.
Algunos ejemplos de Conversión
Muestra cómo hemos convertido algunos ejemplos del tutorial. Cada ejemplo
es un programa completo -- una aplicación o un applet.
Resolver Problemas Comunes con la Conversión
Describe algunos de los problemas más comunes que nos podríamos
encontrar durante la conversión y cómo resolverlos.
Swing
Convertir ButtonDemoApplet
Versión AWT
Versión Swing
Habrás observado que los programas tienen un aspecto diferente.
1. Los tres botones tienen un borde diferente.
2. El Applet usa diferentes fuentes para el Texto.
3. Los botones en el applet Swing tienen iconos y texto.
4. Los botones en el applet Swing muestran el mnemónico de teclado.
5. El applet Swing es más grande.
Las primeras dos diferencias existen simplemente por que el AWT y el
aspecto y comportamiento Java usado en el programa swing dibujan los
botones de forma diferente y tienen diferente fuente por defecto. El
aspecto y comportamiento Java es el aspecto y comportamiento que los
programas Swing usan a menos que el usuario o el programador
especifiquen uno diferente.
Las diferencias 3 y 4 son poeque cuando se convirtió el código nosotros
elegimos aprovecharnos de la característica de los botones Swing no
soportadas por los botones AWT: imágenes y mnemónicos.
La diferencia final es un efecto colateral de las otras cuatro. Si nuestro
programa es una pplet, debemos recordad modificar la etiqueta
<APPLET> para ajustar cualquier cambio de tamaño en nuestro
programa.
Aunque el aspecto de los programas pueda ser diferente, el
comportamiento es el mismo. Cuando el usuario pulsa el botón izquierdo,
se desactiva el botón central y el propio botón izquierdo, y activa el botón
derecho. Cuando el usuario pulsa el botón derecho, se desactiva a sí
mismo y activa los botones central e izquierdo.
La siguiente tabla enlaze el código fuente completo y un fichero HTML que
contiene una etiqueta <APPLET> de ejemplo, para cada versión del
progra,a. Compara el código de la etiqueta <APPLET> para ver las
diferencias entre los dos programas
ButtonDemoApplet.java
left.gif
Swing ButtonDemoApplet.html
middle.gif
LEFT.gif
Convertir AnimatorApplication
Problema: Aunque estoy usando el mismo código grid bag layout que antes, se ve
un componente escrollable pequeño.
● Asegurate de seleccionar las obligaciones del ScrollPane, en vez de las de su
cliente.
Problema: No estoy obteniendo los tipos de eventos que experaba para los
componentes Swing que estoy usando.
● Leete las secciones de trucos de conversión y de cómo usar el componente
que estás usando. Los detalles relevantes del manejo de eventos se cubre en
esas secciones.
Si no puedes encontrar tu problema en esta página, mira en Problemas Comunes
con Componentes Swing.