miércoles
Introducción Muchas veces he leído en los distintos foros referidos a Visual FoxPro, mensajes sobre el tema de crear una barra de herramientas en un formulario. En este artículo expondré un ejemplo de un formulario SDI (Interfaz de un solo documento - Single Document Interface) en el cual crearemos una barra de herramientas en tiempo de ejecución.
Lo necesario Para crear un formulario SDI, Visual FoxPro cuenta con un tipo de formulario llamado "formulario de nivel superior". Estos formularios aparecen como ventanas independientes sobre el escritorio de Windows y también aparecen en la barra de tareas de Windows. Para lograr un formulario de nivel superior, solo debemos configurar la propiedad ShowWindow = 2 (Como formulario de nivel superior). Para crear la barra de herramientas contenida en un formulario de nivel superior, debemos indicar esto configurando la propiedad ShowWindow = 1 (En formulario de nivel superior)
La clase ToolBar Vamos a definir nuestra barra de herramientas programáticamente a partir de la clase ToolBar. Cuando se crea una barra de herramientas, VFP coloca los controles de izquierda a derecha en el orden que aparecen en la definición de la clase. Escribiremos en los métodos Clicks de los controles añadidos, un código simple como un MESSAGEBOX("Hola !") para mostrar el funcionamiento de cada control dentro de la barra de tareas.
El formulario En formulario del ejemplo vamos a incorporar varios botones de comandos: uno crear la barra de herramientas, cuatro para acoplar la barra de herramientas en las distintas posiciones permitidas, y otro para desacoplar la barra de herramientas. Vamos a crear la propiedad personalizada ThisForm.oMiToolBar para crear y mantener la barra de herramientas dentro del alcance del formulario
JSPLITPANE:
JsplitPane se usa para dividir con una barrita divisoria dos y solo dos componentes, mismos que pueden ser alineados de izquierda a derecha o de arriba hacia abajo.
Sus propiedades mas importantes son:
Autoscrolls(), Background(), Border(), Bounds(), Cursor(), DividerSize(), Enabled(), Font(), Foreground(),Insets(), Layouts(), Name(), Opaque(), Orientation(), Text(), ToolTipText(), Visible(), VisibleRect().
Sus escuchadores mas importantes son:
WINDOW: WindowActivated(), WindowClosed(), WindowClosing(), WindowDeactivated(), WindowOpened().
MOUSE: MouseClicked(), MouseDragged(),MouseEntered(), MouseExited(),MouseMoved(), MousePressed(), MouseReleased().
KEY: KeyPressed(), KeyReleased(), KeyTyped().
Text: TEXT_VALUE_CHANGED
Programa Ejemplo:
import java.lang.*;import java.awt.*;import java.awt.event.*;import javax.swing.*;
public class prog8 {
//declaracion, creacion e inicializacion de componentes, objetos y variables
static JFrame ventana= new JFrame();
// abajo se creando con orientacion vertical u horizontal
static JSplitPane panel1 = new JSplitPane(JSplitPane.HORIZONTAL_SPLIT);
static JLabel jl1 = new JLabel("en split1 label1");
static JLabel jl2 = new JLabel("en split2 label2");
// parte principal de programa
public static void main(String[] args)
{ // area de definicion de propiedades de el objeto
ventana.setTitle("mi programa");
ventana.setDefaultCloseOperation(ventana.EXIT_ON_CLOSE);
//cargando splitpanel panel1 con sus dos componentes
panel1.add(jl1); panel1.add(jl2);
// cargando la ventana con splitpanel
ventana.getContentPane().add(panel1,BorderLayout.CENTER);
ventana.pack();
ventana.setVisible(true);
//area de asociacion de objeto-eventos
}; // termina main
} // termina clase
Corrida:
Las barras de desplazamiento tienen dos usos:
- Una barra de desplazamiento puede actuar como un deslizador que el usuario manipula para seleccionar un valor. Un ejemplo de esto está en el programa Converter de la página La Anatomía de un Programa basado en GUI.
- Las barras de desplazamiento le pueden ayudar a mostrar una parte de una región que es demasiado grande para el área de dibujo. Las barras de desplazamiento le permiten al usuario elegir exactamente la parte de la región que es visible. Aquí tiene un ejemplo (podría tardar un poco en cargarse la imagen):
Para crear una barra de desplazamiento, necesitas crear un ejemplar de la clase Scrollbar. También se pueden inicializar los siguientes valores, o bien especificándolos al Constructor de Scrollbar o llamando al método setValues() antes de que la barra de desplazamiento sea visible.
- int orientation
- Indica si la barra de desplazamiento debe ser vertical u horizontal. Especificado con Scrollbar.HORIZONTAL o Scrollbar.VERTICAL.
- int value
- El valor inicial de la barra de desplazamiento. Para barras de desplazamiento que controlan un área desplazable, esto significa el valor x (para las barras horizontales, o el valor y (para las verticales) de la parte del área que es visible cuando el usuario la visita por primera vez. Por ejemplo, el applet anterior arranca en las posiciones 0 tanto vertical como horizontal y la porción de imagen representada empieza en (0,0).
- int visible
- El tamaño en pixels de la porción visible del área desplazable. Este valor, si se selecciona antes de que la barra de desplazamiento sea visible, determina cuantos pixels se desplazará la imagen con una pulsación en la barra de desplazamiento (pero no en el botón). Seleccionar este valor después de que la barra de desplazamiento sea visible no tiene ningún efecto.Después de que la barra de desplazamiento sea visible, se debería utilizar el método setPageIncrement() para obtener el mismo efecto.
- int minimum
- El valor mínimo que puede tener la barra de desplazamiento. Para barras de desplazamiento que controlan áreas desplazables este valor normalmente es 0 (la parte superior izquierda del área).
- int maximum
- El valor máximo que puede tener la barra de desplazamiento. Para barras de desplazamiento que controlan áreas desplazables este valor normalmente es:(la anchura o altura total , en pixels, del componente que está siendo parcialmente representada) - (la anchura o altura visible actualmente del área desplazable).
Aquí tienes el código del applet anterior. Este código define dos clases. La primera es una sencilla subclase de Canvas (ScrollableCanvas) que dibuja una imagen. La segunda es una subclase de Panel (ImageScroller, que realmente desciende de Applet) que crea y conteniene un ScrollableCanvas y dos Scrollbars. Este programa ilustra unos pocos detalles importantes sobre el manejo de un área despalzable:
- El manejo de eventos para una barra de desplazamiento es bastante sencillo. El progama solo debe responder a los eventos de desplazamiento guardando los nuevos valores de la barra de desplazamiento en un lugar accesible para que el componente pueda mostrarse dentro del área desplazable, y luego llamar al método repaint() del Componente.
public boolean handleEvent(Event evt) {
switch (evt.id) {
case Event.SCROLL_LINE_UP:
case Event.SCROLL_LINE_DOWN:
case Event.SCROLL_PAGE_UP:
case Event.SCROLL_PAGE_DOWN:
case Event.SCROLL_ABSOLUTE:
if (evt.target == vert) {
canvas.ty = ((Integer)evt.arg).intValue();
canvas.repaint();
}
if (evt.target == horz) {
canvas.tx = ((Integer)evt.arg).intValue();
canvas.repaint();
}
}
return super.handleEvent(evt);
} - El Componente que se muestra a sí mismo dentro de un área desplazable puede ser muy sencillo. Todo lo que necesita es dibujarse a sí mismo en el origen especificado por los valores de sus barras de desplazamiento. Un Componente puede cambiar su origen (y así no tener que cambiar su código de dibujo normal), poniéndo el siguiente código al principio de sus métodos paint() o update():
g.translate(-tx, -ty);
- Cuando ocurre el desplazamiento, probablemente notarás parpadeo en el área de display, Si no se quiere que esto ocurra, se necesita implementar el método update() en el componente representado, y posiblemente también el doble buffer. Cómo hacer esto se explica en la página Eliminar el Parpadeo.
- Si el área desplazable puede redimensionarse, cuidado con un problema cómun del desplazamiento. Ocurre cuando el usuario desplaza el área hacia abajo y la derecha y luego agranda el área. Si no se tiene cuidado, el ára mostrará un espacio en blanco en su parte inferior derecha. Después de que el usuario desplace y vuelve a la parte inferior derecha, el espacio en blanco no está más allí. Para evitar mostrar un espacio en blanco innecesario, cuando el área desplazable se agranda debe desplazar también el origen del Componente para aprovechar el nuevo espacio disponible. Aquí tienes un ejemplo:
int canvasWidth = canvas.size().width;
//Desplaza todo a la derecha si se está mostrando un espacio vacío
//en el lado derecho.
if ((canvas.tx + canvasWidth) > imageSize.width) {
int newtx = imageSize.width - canvasWidth;
if (newtx < 0) {
newtx = 0;
}
canvas.tx = newtx;
}
JSLIDER:
Se utiliza un JSlider para permitir que el usuario introduzca un valor numérico limitado por una valor máximo y un valor mínimo. Mediante la utilización de un Slider en vez de text field, se eliminan errores de entrada.
Aquí tenemos una imagen de una aplicación que utiliza un Slider para controlar la velocidad de una animación:
Aquí está el código de SliderDemo.java que crea el Slider el programa anterior.JSlider framesPerSecond = new JSlider(JSlider.HORIZONTAL, 0, 30, FPS_INIT);
Por defecto, el espacio para las marcas mayores y menores es cero. Para ver estas marcas, debemos especificar el espaciado de los ticks mayor o menor (o ambos) a un valor distinto de cero y llamar a setPaintTicks(true) (llamar sólo a setPaintTicks(true) no es suficiente). Para salidas estándard, las etiquetas numéricas en la posición marcas mayores seleccionan el mayor espaciado entre marcas, luego se llama setPaintLabels(true). El programa de ejemplo proporciona la etiqueta para sus deslizadores de esta forma. Sin embargo, las etiquetas del Slider son altamente configurables. Puedes ver un ejemplo en Proporcionar Etiquetas para Deslizadores.
framesPerSecond.addChangeListener(new SliderListener());
framesPerSecond.setMajorTickSpacing(10);
framesPerSecond.setMinorTickSpacing(1);
framesPerSecond.setPaintTicks(true);
framesPerSecond.setPaintLabels(true);
framesPerSecond.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
. . .
//add the slider to the content pane
contentPane.add(framesPerSecond);Cuando se mueve el deslizador, se llama al método stateChanged del ChangeListener del deslizador, cambiando la velocidad de la animación:
class SliderListener implements ChangeListener {
Si movemos el deslizador hasta cero, la animación se para.
public void stateChanged(ChangeEvent e) {
JSlider source = (JSlider)e.getSource();
if (!source.getValueIsAdjusting()) {
int fps = (int)((JSlider)e.getSource()).getValue();
if (fps == 0) {
if (!frozen) stopAnimation();
} else {
delay = 1000 / fps;
timer.setDelay(delay);
if (frozen) startAnimation();
}
}
}
}Observa que el método stateChanged sólo cambia la velocidad de la animación si getValueIsAdjusting devuelve false. Muchos eventos change se disparan cuando el usuario mueve el deslizador. Este programa sólo está interesado en el resultado final de la acción del usuario.
Porporcionar Etiquetas para Deslizadores
Para mostrar etiquetas en un deslizador, debemos llamar a setPaintLabels(true) y proporcionar un conjunto de etiquetas que indiquen las posiciones y valores para cada etiqueta. Las etiquetas pueden especificarse utilizando una de las siguientes técnicas:
- Llamar a setMajorTickSpacing con un valor distinto de cero. Haciéndolo de esta manera, las etiquetas idendifican el valor de cada marca de pulsación mayor. Esta es la técnica utiliza por SliderDemo.java.
- Crear un Hashtable que contenga el valor para cada etiqueta y su posición. Se proporciona el Hashtable como un argumento a setLabelTable.
SliderDemo2.java, utiliza esta técnica:
Aquí está el código de SliderDemo2.java que crea el deslizador:
//Create the sliderEste 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.
JSlider framesPerSecond = new JSlider(JSlider.VERTICAL, 0, 30, FPS_INIT);
framesPerSecond.addChangeListener(new SliderListener());
framesPerSecond.setMajorTickSpacing(10);
framesPerSecond.setPaintTicks(true);
//Create the label table
Dictionary labelTable = new Hashtable();
labelTable.put( new Integer( 0 ), new JLabel("Stop") );
labelTable.put( new Integer( 3 ), new JLabel("Slow") );
labelTable.put( new Integer( 30 ), new JLabel("Fast") );
framesPerSecond.setLabelTable( labelTable );
framesPerSecond.setPaintLabels(true);
framesPerSecond.setBorder(BorderFactory.createEmptyBorder(0,0,0,10));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.
Ajsute Fino de la Apariencia del Deslizador Método Propósito void setValue(int)
int getValue()Seleciona u obtiene el valor actual del Slider. El marcador del deslizador está en esta posición. void setOrientation(int)
int getOrientation()Seleciona u obtiene la orientación del Slider. Los posibles valores son JSlider.HORIZONTAL o JSlider.VERTICAL void setInverted(boolean)
boolean getInverted()Seleciona u obtiene si el máximo se muestra a la izquierda en un deslizador horizontal o abajo en uno vertical, por lo tanto invierte el rango del deslizador. void setMinimum(int)
int getMinimum()
void setMaximum(int)
int getMaximum()Seleciona u obtiene los valores máximos o mínimos del deslizador. Juntos selecionan u obtienen el rango del deslizador. void setMajorTickSpacing(int)
int getMajorTickSpacing()
void setMinorTickSpacing(int)
int getMinorTickSpacing()Seleciona u obtiene el rango entre marcas mayores y menores. Debemos llamar a setPaintTicks(true) para que aparezcan las marcas. void setPaintTicks(boolean)
boolean getPaintTicks()Seleciona u obtiene si se dibujan las marcas en el deslizador. void setLabelTable(Dictionary)
Dictionary getLabelTable()Seleciona u obtiene las etiquetas para el deslizador. Debemos llamar a setPaintLabels(true) para que aparezcan las etiquetas. createStandardLabels es un método de conveniencia para crear un conjunto de etiquetas estándard. void setPaintLabels(boolean)
boolean getPaintLabels()Seleciona u obtiene si se dibujan las etiquetas de un deslizador. Las etiquetas se seleccionan con setLabelTable o configurando el espaciado entre marcas mayores.
En general, no se crea directamente un objeto JRootPane. En su lugar, se obtiene un JRootPane (tanto si se quiere como si no!) cuando se ejemplariza un JInternalFrame o uno de los contenedores Swing de alto nivel -- JApplet, JDialog, JFrame, y JWindow.
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.
Método | Propósito |
---|---|
JRootPane getRootPane() (en JApplet, JDialog, JFrame, JInternalFrame, y JWindow) | Obtiene el panel raíz del applet, dialog, frame, internal frame, o window. |
JRootPane SwingUtilities.getRootPane(Component) | Si el componente tiene un panel raíz, lo devuelve. Si no es así, devuelve el panel raíz (si existe) que contiene el componente. |
JRootPane getRootPane() (en JComponent) | Invoca al método SwingUtilitiesgetRootPane sobre JComponent. |
void setDefaultButton(JButton) JButton getDefaultButton() | Selecciona u obtiene qué botón (si existe) es el botón por defecto del panel raíz. Una acción específica del aspecto y comportamiento, como pulsar ENTER, hace que se realice la acción del botón. |
Método Propósito setGlassPane(Component)
Component getGlassPane()
(en JApplet, JDialog, JFrame, JInternalFrame, JRootPane, y JWindow) Selecciona u obtiene elpanel de cristal.
Método Propósito setContentPane(Container)
Container getContentPane()
(en JApplet, JDialog, JFrame, JInternalFrame, JRootPane, y JWindow) Selecciona u obtiene el panel de contenido.
JPROGRESSBAR.
Una barra de progreso que muestra gráficamente qué cantitad total de la tarea se ha terminado.
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:
JOPTIONPANE:
Es un componente al estilo Pop Up que sirve como un promt o ventana de datos donde se puede pedir o desplegar información.
Siempre que pensemos usar la clase JOptionPane, devemos primero importarla.
import javax.swing.JOptionPane;
———————————————————————————————————————————
Solicitar datos:
Al solicituar informacion, este se guarda en un String usando el metodo showInputDialog
Codigo:
String nombre;
nombre = JOptionPane.showInputDialog("Ingrese su nombre");
———————————————————————————————————————————
Mostrar mensaje:
Para mostrar un mensaje en una ventana solo debemos usar el metodo showMessageDialog
Codigo:
JOptionPane.showMessageDialog(null,"Hola"+nombre+" Bienvenido ! !");
showMessageDialog
Es un diálogo simple que presenta un boton de “Aceptar”. Se puede especificar fácilmente el mensaje, el icono, y el título que el diálogo exhibe. Aquí están algunos ejemplos del showMessageDialog que se usan:
Codigo:
JOptionPane.showMessageDialog(ventana, “El cielo es de color azul.”, “Dialogo sencillo”, JOptionPane.INFORMATION_MESSAGE);
Codigo:
JOptionPane.showMessageDialog(ventana, “Quieres usar el Question Dialog ”+ “(como esto)\n” + “para preguntar, OK?”, “Dialogo sencillo”, JOptionPane.QUESTION_MESSAGE);
Codigo:
JOptionPane.showMessageDialog(ventana,“El cielo es de color azul.”, “Dialogo sencillo”, JOptionPane.ERROR_MESSAGE);
Codigo:
JOptionPane.showMessageDialog(ventana, “El cielo es de color azul.”, “Dialogo sencillo”, JOptionPane.INFORMATION_MESSAGE, icono);
JOptionPane.showMessageDialog(ventana, “El cielo es de color azul.”, “Dialogo sencillo”, JOptionPane.PLAIN_MESSAGE);
Los argumentos:
———————————————————————————————————————————
- Component parentComponent: Es el componente padre del diálogo, si el argumento pasa como null simplemente el diálogo se mostrará en centro de la pantalla y no tendra el foco principal si hay JFrame o alguna otra ventana
- Object message: El mensaje a mostrar, es el texto principal
- String title: El titulo que lleva el diálogo en la barra de tareas
- int optionType: El tipo de diálogo, puede ser del tipo DEFAULT_OPTION, YES_NO_OPTION, YES_NO_CANCEL_OPTION, OK_CANCEL_OPTION
- int messageType: El tipo de icono que tendrá el diálogo, puede ser PLAIN_MESSAGE (sin icono), ERROR_MESSAGE, INFORMATION_MESSAGE, WARNING_MESSAGE, QUESTION_MESSAGE
- Icon icon: El icono personalizado que tendra el diálogo
- Object[] options: Estas son las opciones que tendrá el diálogo, son útiles cuando creamos nuestros propios diálogos
Normalmente, los frames internos se muestran dentro de un JDesktopPane. JDesktopPane es una subclase de JLayeredPane al que se le ha añadido el API para manejar el solapamiento de múltiples frames internos. Generalmente, se pone el panel superior dentro del panel de contenido de un JFrame. Para más información sobre el uso de API que JDesktopPane hereda de JLayeredPane, puedes ver Cómo usar LayeredPane.
Aquí podemos ver una imagen de una aplicación que tiene dos frames internos dentro de un frame normal.
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).
JTABBEDPANE
JTabbedPane tp1 = new JTabbedPane();Para poder adicionar componentes al JTabbedPane es indispensable crear un JPanel una vez creado, se le adicionan los componentes directamente, para que posteriormente JPanel sea adicionado a JTabbedPane, ponerle un ícono a las pestañas de JTabbedPane es opcional, por ejemplo en la imagen anterior podemos ver el ícono de GRADO 11, en caso de que se desee agregar un ícono se declara dentro de todo el Tabbed Pane de la siguiente forma:
ImageIcon icon = new ImageIcon("icono.jpg");
JPanel p1 = new JPanel();
JTextArea info = new JTextArea(
"En este programa podrá encontrar imágenes" +
" de estudiantes del grado Once, solo señale en la parte superior" +
" el nombre de la persona que desea ver, en caso que quiera" +
" obtener mas información de la persona o del lugar donde fue adquirida la imagen"+
" pulsa el botón que esta en la parte derecha del panel (Información)"
);
p1.add(info, BorderLayout.NORTH);
creditos = new JButton("Créditos");
creditos.addActionListener(this);
creditos.setActionCommand(SHOW);
creditos.setEnabled(true);
p1.add(creditos, BorderLayout.SOUTH);
tp1.addTab("Información", icon, p1, "Información del programa");
Otras Opciones de JTabbedPane
Estas Opciones no fueron implementadas en el Organizador de Imágenes
Ejemplo 1-1. Métodos para presentar una pestaña
addTab(String, Icon, Component, String) addTab(String, Icon, Component) addTab(String, Component)
Ejemplo 1-2. Método para poner una pestaña sobre otra
![]() | La primera pestaña siempre tiene índice 0 |
martes
Utilizar en Swing un árbol, como los que se despliegan en muchas de las ventanas de los sistemas operativos al uso, es tan simple como escribir:
add( new JTree( new Object[]{ "este","ese","aquel" } ) );
Esto crea un arbolito muy primitivo; sin embargo, el API de Swing para árboles es inmenso, quizá sea uno de los más grandes. En principio parece que se puede hacer cualquier cosa con árboles, pero lo cierto es que si se van a realizar tareas con un cierto grado de complejidad, es necesario un poco de investigación y experimentación, antes de lograr los resultados deseados.
Afortunadamente, como en el término medio está la virtud, en Swing, JavaSoft proporciona los árboles "por defecto", que son los que generalmente necesita el programador la mayoría de las veces, así que no hay demasiadas ocasiones en que haya que entrar en las profundidades de los árboles para que se deba tener un conocimiento exhaustivo del funcionamiento de estos objetos.
El ejemplo java1414.java, utiliza estos árboles predefinidos, para presentar un árbol en un panel. Cuando se pulsa el botón, se añade un nuevo sub-árbol a partir del nodo que está seleccionado; si no hay ninguno, se añade en el raíz.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.tree.*;
// Esta clase coge un array de Strings, haciendo que el primer elemento
// del array sea un nodo y el resto sean ramas de ese nodo
// Con ello se consiguen las ramas del árbol general cuando se pulsa
// el botón de test
class Rama {
DefaultMutableTreeNode r;
public Rama( String datos[] ) {
r = new DefaultMutableTreeNode( datos[0] );
for( int i=1; i < datos.length; i++ )
r.add( new DefaultMutableTreeNode( datos[i] ) );
}
public DefaultMutableTreeNode node() {
return( r );
}
}
public class java1414 extends JPanel {
String datos[][] = {
{ "Colores","Rojo","Verde","Azul" },
{ "Sabores","Salado","Dulce","Amargo" },
{ "Longitud","Corta","Media","Larga" },
{ "Intensidad","Alta","Media","Baja" },
{ "Temperatura","Alta","Media","Baja" },
{ "Volumen","Alto","Medio","Bajo" },
};
static int i=0;
DefaultMutableTreeNode raiz,rama,seleccion;
JTree arbol;
DefaultTreeModel modelo;
public java1414() {
setLayout( new BorderLayout() );
raiz = new DefaultMutableTreeNode( "raiz" );
arbol = new JTree( raiz );
// Se añade el árbol y se hace sobre un ScrollPane, para
// que se controle automáticamente la longitud del árbol
// cuando está desplegado, de forma que aparecerá una
// barra de desplazamiento para poder visualizarlo en su
// totalidad
add( new JScrollPane( arbol ),BorderLayout.CENTER );
// Se obtiene el modelo del árbol
modelo =(DefaultTreeModel)arbol.getModel();
// Y se añade el botón que va a ir incorporando ramas
// cada vez que se pulse
JButton botonPrueba = new JButton( "Pulsame" );
botonPrueba.addActionListener( new ActionListener() {
public void actionPerformed( ActionEvent evt ) {
if( i < datos.length ) {
rama = new Rama( datos[i++] ).node();
// Control de la útlima selección realizada
seleccion = (DefaultMutableTreeNode)
arbol.getLastSelectedPathComponent();
if( seleccion == null )
seleccion = raiz;
// El modelo creará el evento adecuado, y en respuesta
// a él, el árbol se actualizará automáticamente
modelo.insertNodeInto( rama,seleccion,0 );
}
}
} );
// Cambio del color del botón
botonPrueba.setBackground( Color.blue );
botonPrueba.setForeground( Color.white );
// Se crea un panel para contener al botón
JPanel panel = new JPanel();
panel.add( botonPrueba );
add( panel,BorderLayout.SOUTH );
}
public static void main( String args[] ) {
JFrame frame = new JFrame( "Tutorial de Java, Swing" );
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) {
System.exit( 0 );
}
});
frame.getContentPane().add( new java1414(),BorderLayout.CENTER );
frame.setSize( 200,500 );
frame.setVisible( true );
}
}
La figura siguiente muestra la ventana de ejecución del ejemplo, una vez pulsado el botón varias veces y con algunos de los sub-árboles desplegados.
En la aplicación, la primera clase, Rama, coge un array de String y genera uno de los nodos el árbol, con la primera cadena como raíz y el resto como sus hojas. Posteriormente, se pueden hacer llamadas al método node() para generar la raíz de esta rama.
La clase JTree contiene un array de String de dos dimensiones, a partir del cual salen las ramas, y un contador para moverse a través del array. Los objetos DefaultMutableTreeNode contienen los nodos, pero la representación física sobre la pantalla está controlada por la clase JTree y su modelo asociado, el DefaultTreeModel. Cuando el JTree se incorpora al Frame, es incrustado automáticamente en un JScrollPane, para proporcionar desplazamiento o scroll automático al árbol.
El JTree está controlado a través de un modelo. Cuando se hace un cambio en el modelo, este modelo genera un evento que hace que el JTree realice las actualizaciones necesarias en la representación visible del árbol. En el método init(), en el caso de un applet, o en el constructor, en el caso más general, el modelo que se utiliza es capturado a través del método getModel(). Cuando se pulsa un botón, se crea una nueva rama. Entonces, el Componente seleccionado actual será encontrado (o se convertirá en el raíz, en el caso de que no se encuentre) y el método insertNodeInfo() del modelo hará el trabajo de cambiar el árbol y hacer que se actualice.
En la mayor parte de las ocasiones, un ejemplo como el anterior es capaz de solucionar la mayoría de los problemas de implementación que se propongan. Sin embargo, los árboles tienen el poder de hacer casi cualquier cosa que se pueda imaginar; por ejemplo, en el programa anterior se puede sustituir la palabra "default" por cualquier otra clase para proporcionar un entorno de funcionamiento diferente. Pero hay que andar con cuidado, porque muchas de estas clases tienen un interfaz muy intenso, por lo que puede llevar mucho tiempo el comprender todo el intríngulis de los árboles.
Ya en la discusión de JList, se introdujeron los modelos de datos propios, es decir, una forma determinada de controlas el funcionamiento de uno de los Componentes de Swing. Pero no solamente las listas permiten hacer esto, los árboles también soportan estos modelos, aunque en este caso, debido a la naturaleza jerárquica de los árboles, el modelo es bastante más complejo.
En el ejemplo java1415.java se recrea un árbol que contiene las cartas de una baraja, utilizando un modelo de datos propio para la presentación y manipulación de cada uno de los elementos de las ramas del árbol.
En el código del ejemplo, se incluye la clase anidada que es la que controla cada uno de los elementos.
public class MiRendererDeArbol extends JLabel implements TreeCellRenderer {
private ImageIcon imgBaraja;
private ImageIcon[] imgPalos;
private ImageIcon[] imgCartas;
private boolean seleccionado;
public MiRendererDeArbol() {
// Cargamos las imgenes de las cartas
imgBaraja = new ImageIcon( "_palos.gif" );
imgPalos = new ImageIcon[4];
imgPalos[0] = new ImageIcon( "_copas.gif" );
imgPalos[1] = new ImageIcon( "_oros.gif" );
imgPalos[2] = new ImageIcon( "_espadas.gif" );
imgPalos[3] = new ImageIcon( "_bastos.gif" );
imgCartas = new ImageIcon[10];
imgCartas[0] = new ImageIcon( "_as.gif" );
imgCartas[1] = new ImageIcon( "_dos.gif" );
imgCartas[2] = new ImageIcon( "_tres.gif" );
imgCartas[3] = new ImageIcon( "_cuatro.gif" );
imgCartas[4] = new ImageIcon( "_cinco.gif" );
imgCartas[5] = new ImageIcon( "_seis.gif" );
imgCartas[6] = new ImageIcon( "_siete.gif" );
imgCartas[7] = new ImageIcon( "_diez.gif" );
imgCartas[8] = new ImageIcon( "_once.gif" );
imgCartas[9] = new ImageIcon( "_doce.gif" );
}
public Component getTreeCellRendererComponent( JTree arbol,
Object valor,boolean seleccionado,boolean expandido,
boolean rama,int fila,boolean conFoco ) {
// Hay que encontrar el nodo en que estamos y coger el
// texto que contiene
DefaultMutableTreeNode nodo = (DefaultMutableTreeNode)valor;
String texto = (String)nodo.getUserObject();
this.seleccionado = seleccionado;
// Se fija el color de fondo en función de que esté o no
// seleccionada la celda del árbol
if( !seleccionado )
setForeground( Color.black );
else
setForeground( Color.white );
// Fijamos el icono que corresponde al texto de la celda, para
// presentar la imagen de la carta que corresponde a esa celda
if( texto.equals( "Palos" ) )
setIcon( imgBaraja );
else if( texto.equals( "Copas" ) )
setIcon( imgPalos[0] );
else if( texto.equals( "Oros" ) )
setIcon( imgPalos[1] );
else if( texto.equals( "Espadas" ) )
setIcon( imgPalos[2] );
else if( texto.equals( "Bastos" ) )
setIcon( imgPalos[3] );
else if( texto.equals( "As" ) )
setIcon( imgCartas[0] );
else if( texto.equals( "Dos" ) )
setIcon( imgCartas[1] );
else if( texto.equals( "Tres" ) )
setIcon( imgCartas[2] );
else if( texto.equals( "Cuatro" ) )
setIcon( imgCartas[3] );
else if( texto.equals( "Cinco" ) )
setIcon( imgCartas[4] );
else if( texto.equals( "Seis" ) )
setIcon( imgCartas[5] );
else if( texto.equals( "Siete" ) )
setIcon( imgCartas[6] );
else if( texto.equals( "Sota" ) )
setIcon( imgCartas[7] );
else if( texto.equals( "Caballo" ) )
setIcon( imgCartas[8] );
else if( texto.equals( "Rey" ) )
setIcon( imgCartas[9] );
// A continuación del icono, ponemos el texto
setText( texto );
return( this);
}
// Sobreescribimos el método paint() para fijar el color de
// fondo. Normalmente, un JLabel puede pintar su propio fondo,
// pero, seguramente debido aparentemente a un bug, o a una
// limitación en el TreeCellRenderer, es necesario recurrir
// al método paint() para hacer esto
public void paint( Graphics g ) {
Color color;
Icon currentI = getIcon();
// Fijamos el colos de fondo
color = seleccionado ? Color.red : Color.white;
g.setColor( color );
// Rellenamos el rectángulo que ocupa el texto sobre la
// celda del árbol
g.fillRect( 0,0,getWidth()-1,getHeight()-1 );
super.paint( g );
}
}
La ejecución del ejemplo, genera una imagen como la que se reproduce a continuación, en donde se ha desplegado una de las ramas del árbol y se ha seleccionado uno de sus elementos.
La clase principal de la aplicación crea un árbol que contiene a cada una de las cartas en uno de los palos de la baraja, y no tiene más misterio. La clase anidada MiRendererDeArbol, es la que implementa el comportamiento que van a tener cada uno de los elementos de las ramas del árbol. Como se puede observar, esta circunstancia permite la inclusión de gráficos o cualquier cambio, como el de la fuente de caracteres, en elementos específicos del árbol. Por ejemplo, puede resultar interesante en una aplicación, el presentar los elementos de un nivel superior en negrilla para resaltar su importancia, o se puede querer añadir una imagen para ser más explicativos. Cualquier cosa de estas, se puede implementar a través de un modelo de datos propio.
En el programa, por ejemplo, los elementos de nivel superior, correspondientes a los palos de la baraja, incluyen la carta que muestra el palo, y a cada una de las cartas individuales, también se les ha añadido el gráfico que las representa. Y en el código, lo único especial es la línea en la cual se le notifica al árbol que dispone de un controlador propio e independiente para la manipulación de las celdas o elementos del árbol.
arbol.setCellRenderer( new MiRendererDeArbol() );
La clase anidada implementa un constructor para la carga de las imágenes, a fin de ahorrar tiempo a la hora de la ejecución. El método getTreeCellRendererComponent(), que debe ser proporcionado a requerimiento de la implementación de la clase TreeCellRenderer utilizada por la clase anidada, es el responsable del dibujo de los elementos del árbol. En este caso, este método determina cuál es la imagen que corresponde al elemento del árbol, basándose en el texto asociado al elemento, y le asigna el icono correspondiente. Además, fija el color de fondo de la celda que contiene al elemento, en función de que esté seleccionado o no.
Con esto último hay un problema. El color de fondo de un elemento del árbol no puede fijarse dentro del método de la clase que implementa el modelo, o por lo menos, si se hace así no tiene efecto alguno. Puede que sea una limitación o un problema de Swing que piensan corregir, pero lo cierto es que esto no ocurre en otros casos, como pueden ser las listas o las tablas. Para evitar el problema, es necesario incluir el método paint() dentro de la clase que implementa el controlador de las celdas.
JTABLE:La JTable controla cómo se presentan los datos, siendo el TableModel quien controla los datos en sí mismos. Para crear una JTable habrá pues que crear un TableModel antes, normalmente. Se puede implementar, para ello, el interfaz TableModel, pero es mucho más simple heredar de la clase ayuda AbstractTableModel. El ejemplo java1416.java muestra esta circunstancia.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.table.*;
import com.sun.java.swing.event.*;
// El Modelo de la Tabla es el que controla todos los
// datos que se colocan en ella
class ModeloDatos extends AbstractTableModel {
Object datos[][] = {
{"uno","dos","tres","cuatro"},
{"cinco","seis","siete","ocho"},
{"nueve","diez","once","doce"},
};
// Esta clase imprime los datos en la consola cada vez
// que se produce un cambio en cualquiera de las
// casillas de la tabla
class TablaListener implements TableModelListener {
public void tableChanged( TableModelEvent evt ) {
for( int i=0; i < datos.length; i++ ) {
for( int j=0; j < datos[0].length; j++ )
System.out.print( datos[i][j] + " " );
System.out.println();
}
}
}
// Constructor
ModeloDatos() {
addTableModelListener( new TablaListener() );
}
// Devuelve el número de columnas de la tabla
public int getColumnCount() {
return( datos[0].length );
}
// Devuelve el número de filas de la tabla
public int getRowCount() {
return( datos.length );
}
// Devuelve el valor de una determinada casilla de la tabla
// identificada mediante fila y columna
public Object getValueAt( int fila,int col ) {
return( datos[fila][col] );
}
// Cambia el valor que contiene una determinada casilla de
// la tabla
public void setValueAt( Object valor,int fila,int col ) {
datos[fila][col] = valor;
// Indica que se ha cambiado
fireTableDataChanged();
}
// Indica si la casilla identificada por fila y columna es
// editable
public boolean isCellEditable( int fila,int col ) {
return( true );
}
}
public class java1416 extends JPanel {
public java1416() {
setLayout( new BorderLayout() );
JTable tabla = new JTable( new ModeloDatos() );
// La tabla se añade a un ScrollPane para que sea éste el
// que controle automáticamente en tamaño de la tabla,
// presentando una barra de desplazamiento cuando sea
// necesario
JScrollPane panel = new JScrollPane( tabla );
add( panel,BorderLayout.CENTER );
}
public static void main(String args[]) {
JFrame frame = new JFrame( "Tutorial de Java, Swing" );
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) {
System.exit( 0 );
}
} );
frame.getContentPane().add( new java1416(),BorderLayout.CENTER );
frame.setSize( 200,200 );
frame.setVisible( true );
}
}
En el ejemplo, para no complicar la cosa, DataModel es quien contiene el conjunto de datos, pero también se podrían haber cogido de una base de datos. El constructor añade un receptor de eventos de tipo TableModelListener que va a imprimir el contenido de la tabla cada vez que se produzca un cambio. El resto de los métodos utilizan la notación de los Beans y son utilizados por el objeto JTable cuando se quiere presentar la información del DataModel. AbstractTableModel proporciona por defecto los métodos setValueAt() y isCellEditable() que se utilizan para cambiar los datos, por lo que si se quiere realizar esta operación, no queda más remedio que sobrescribir los dos métodos.
La figura siguiente muestra la Tabla obtenida tras la ejecución del programa en donde se ha editado la casilla correspondiente a la segunda fila y columna B.
Una vez que se tiene un TableModel, ya sólo resta colocarlo en el constructor de JTable. Todos los detalles de presentación, edición y actualización están ocultos al programador. En este ejemplo, se coloca la JTable en un JScrollPane, por lo que es necesario un método especial en JTable.
Las tablas pueden soportar un comportamiento más complejo. En el ejemplo java1417.java, se utiliza un método para cargar un array de ocho columnas por un ciento de filas y, posteriormente, la tabla es configurada para que muestre solamente las líneas verticales y permita la selección simultánea de la fila y columna en que se encuentre la celda marcada.
import java.awt.*;
import java.awt.event.*;
import java.util.*;
import com.sun.java.swing.*;
import com.sun.java.swing.table.*;
class java1417 extends JPanel {
private JTable tabla;
private JScrollPane panelScroll;
private String titColumna[];
private String datoColumna[][];
public java1417() {
setLayout( new BorderLayout() );
// Creamos las columnas y las cargamos con los datos que van a
// aparecer en la pantalla
CreaColumnas();
CargaDatos();
// Creamos una instancia del componente Swing
tabla = new JTable( datoColumna,titColumna );
// Aquí se configuran algunos de los parámetros que permite
// variar la JTable
tabla.setShowHorizontalLines( false );
tabla.setRowSelectionAllowed( true );
tabla.setColumnSelectionAllowed( true );
// Cambiamos el color de la zona seleccionada (rojo/blanco)
tabla.setSelectionForeground( Color.white );
tabla.setSelectionBackground( Color.red );
// Incorporamos la tabla a un panel que incorpora ya una barra
// de desplazamiento, para que la visibilidad de la tabla sea
// automática
panelScroll = new JScrollPane( tabla );
add( panelScroll, BorderLayout.CENTER );
}
// Creamos las etiquetas que sirven de título a cada una de
// las columnas de la tabla
public void CreaColumnas() {
titColumna = new String[8];
for( int i=0; i < 8; i++ ) {
titColumna[i] = "Col: "+i;
}
}
// Creamos los datos para cada uno de los elementos de la tabla
public void CargaDatos() {
datoColumna = new String[100][8];
for( int iY=0; iY < 100; iY++ ) {
for( int iX=0; iX < 8; iX++ ) {
datoColumna[iY][iX] = "" + iX + "," + iY;
}
}
}
public static void main( String args[] ) {
JFrame ventana = new JFrame( "Tutorial de Java, Swing" );
ventana.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ){
System.exit( 0 );
}
} );
ventana.getContentPane().add( new java1417(),BorderLayout.CENTER );
ventana.setSize( 300,180 );
ventana.setVisible( true );
}
}
La figura siguiente muestra el resultado de la ejecución del ejemplo. Obsérvese que cuano se selecciona un elemento individual de la tabla, aparece una selección en cruz de fila y columna, centrada en la celda que se ha marcado. En este ejemplo los colores de fondo y texto para la región seleccionada se han alterado, que es otra de las facilidades que soporta el componente JTable, el cambio de color para un área de selección.
Aunque el ejemplo contiene un array relativamente grande de datos, la clase JTable no manipula demasiado bien grandes cantidades de información, resultando un rendimiento bastante pobre cuando se sobrepasan los 2000 elementos.
JSCROLLPANE:Cuando un componente ocupa mucho espacio en pantalla o contiene mucha información, un JSCROLLPANE permite asociarle una pequeña vista o ventana deslizable o corrediza que permite solo que se vea una parte de dicho componente.
Un JSCROLLPANE, tambien puede asociarse a otros tipos de panels que contengan muchos componentes.
Algunas sus propiedades mas importantes son:
Autoscrolls(), Background(), Border(), Bounds(), Cursor(), Enabled(), Font(), Foreground(),Insets(), Name(), Opaque(), ToolTipText(), ViewPortBorder(), Visible(), VisibleRect().
Sus escuchadores mas importantes son:
WINDOW: WindowActivated(), WindowClosed(), WindowClosing(), WindowDeactivated(), WindowOpened().
MOUSE: MouseClicked(), MouseDragged(),MouseEntered(), MouseExited(),MouseMoved(), MousePressed(), MouseReleased().
KEY: KeyPressed(), KeyReleased(), KeyTyped().
Programa ejemplo:
import java.lang.*;import java.awt.*;import java.awt.event.*;import javax.swing.*;
public class prog9 {
//declaracion, creacion e inicializacion de componentes, objetos y variables
static JFrame ventana= new JFrame();
static JScrollPane panel1 = new JScrollPane();
static JTextField jt1 = new JTextField(80);
// parte principal de programa
public static void main(String[] args)
{ // area de definicion de propiedades de el objeto
ventana.setTitle("mi programa");
ventana.setDefaultCloseOperation(ventana.EXIT_ON_CLOSE);
//cargando scrollpane panel1 con un componente grandote
panel1.setViewportView(jt1);
// cargando la ventana con el scrollpanel
ventana.getContentPane().add(panel1,BorderLayout.CENTER);
ventana.pack(); ventana.setVisible(true);
//area de asociacion de objeto-eventos
}; // termina main
} // termina clase
De momento el unico componente grandote a usar es el textfield con muchos caracteres, mas adelante se estudiaran componentes mas apropiados para este tipo de panel.
Corrida:
JPOPUPMENU:La implementación de JPopupMenu resulta un tanto extraña: antes de nada hay que llamar al método enableEvents() y seleccionar los eventos del ratón, en vez de utilizar un receptor de eventos como sería de esperar. Es decir, es posible añadir un receptor de eventos del ratón, pero el evento asociado, MouseEvent, no es capaz de devolver true desde el método isPopupTrigger(); aunque también puede que sea porque el JDK todavía está en fase beta; pero vamos, el comportamiento es ciertamente raro. A pesar de ello, el ejemplo java1412.java, sí que produce el efecto deseado de presentar el menú en la pantalla tal como se muestra:
ante la llegada del evento correspondiente a la activación del menú.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
public class java1412 extends JPanel {
JPopupMenu popup = new JPopupMenu();
JTextField txt = new JTextField( 10 );
public java1412() {
add( txt );
ActionListener al = new ActionListener() {
public void actionPerformed( ActionEvent evt ){
txt.setText( ((JMenuItem)evt.getSource()).getText() );
}
};
JMenuItem elemento = new JMenuItem( "Carpanta" );
elemento.addActionListener( al );
popup.add( elemento );
elemento = new JMenuItem( "Rompetechos" );
elemento.addActionListener( al );
popup.add( elemento );
elemento = new JMenuItem( "Otilio" );
elemento.addActionListener( al );
popup.add( elemento );
popup.addSeparator();
elemento = new JMenuItem( "Mortadelo" );
elemento.addActionListener( al );
popup.add( elemento );
enableEvents( AWTEvent.MOUSE_EVENT_MASK );
}
protected void processMouseEvent( MouseEvent evt ){
if( evt.isPopupTrigger() )
popup.show( evt.getComponent(),evt.getX(),evt.getY() );
else
super.processMouseEvent( evt );
}
public static void main( String args[] ) {
JFrame frame = new JFrame( "Tutorial de Java, Swing" );
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) {
System.exit( 0 );
}
});
frame.getContentPane().add( new java1412(),BorderLayout.CENTER );
frame.setSize( 200,150 );
frame.setVisible( true );
}
}
El mismo ActionListener es el que se añade a cada JMenuItem, que coge el texto de la etiqueta del menú y la inserta en el JTextField.
JPANEL:El siguiente ejemplo java1418.java, se aprovecha de algunos de los ejemplos anteriores para poder implementar los diferentes paneles. Todos se construyen como descendientes de JPanel, así que en el programa se colocará cada uno de los ejemplos anteriores en su propio panel dentro del JTabbedPane.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
import com.sun.java.swing.border.*;
public class java1418 extends JPanel {
static Object objetos[][] = {
{ "AWT-Clon",java1401.class },
{ "Bordes",java1402.class },
{ "Botones",java1404.class },
{ "Grupo de Botones",java1406.class },
{ "Listas y Combo",java1407.class },
{ "Barras",java1413.class },
{ "Arbol",java1414.class },
{ "Tabla",java1416.class },
};
static JPanel creaPanel( Class clase ) {
String titulo = clase.getName();
titulo = titulo.substring( titulo.lastIndexOf('.') + 1 );
JPanel panel = null;
try {
panel = (JPanel)clase.newInstance();
} catch( Exception e ) {
System.out.println( e );
}
panel.setBorder( new TitledBorder( titulo ) );
return( panel );
}
public java1418() {
setLayout( new BorderLayout() );
JTabbedPane pestana = new JTabbedPane();
for( int i=0; i < objetos.length; i++ ) {
pestana.addTab( (String)objetos[i][0],
creaPanel( (Class)objetos[i][1] ) );
}
add( pestana,BorderLayout.CENTER );
pestana.setSelectedIndex( objetos.length/2 );
}
public static void main( String args[] ) {
JFrame frame = new JFrame( "Tutorial de Java, Swing" );
frame.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) {
System.exit( 0 );
}
} );
frame.getContentPane().add( new java1418(),BorderLayout.CENTER );
frame.setSize( 460,350 );
frame.setVisible( true );
}
}
Se ha utilizado un array para la configuración: el primer elemento es el objeto String que será colocado en la pestaña y el segundo corresponde al objeto de la clase JPanel que será presentado dentro del correspondiente Panel. En el constructor del ejemplo se puede observar que se utilizan los dos métodos importantes del JTabbedPane: addTab() que crea una nueva pestaña y setSelectedIndex() que indica el panel que se va a presentar en primer lugar al arrancar el programa; en este caso se selecciona uno de en medio para mostrar que no es necesario comenzar siempre por el primero. La figura siguiente reproduce esta ventana inicial, en la que aparecen las barras de desplazamiento al igual que se ilustraba uno de los ejemplos anteriores de este capítulo.
En la llamada al método addTab() se le proporciona la cadena que debe colocar en la pestaña y cualquier Componente del AWT. No es necesario que sea un JCompomponent, sino cualquier Componente del AWT, entre los cuales se encuentra, evidentemente, el JComponent, que deriva del Component del AWT. El Componente se presentará sobre el panel y ya no será necesario ningún control posterior, el JTabbedPane se encarga de todo.
El trozo más interesante del código del ejemplo es el correspondiente al método creaPanel() que coge el objeto Class de la clase que se quiere crear y utiliza el método newInstance() para crear uno, moldeándolo a JPanel; desde luego, esto asume que la clase que se quiere añadir debe heredar de JPanel, sino no serviría de nada. Añade un TitledBorder que contiene el nombre de la clase y devuelve el resultado como un JPanel para que sea utilizado en addTab().
static JPanel creaPanel( Class clase ) {
String titulo = clase.getName();
titulo = titulo.substring( titulo.lastIndexOf('.') + 1 );
JPanel panel = null;
try {
panel = (JPanel)clase.newInstance();
} catch( Exception e ) {
System.out.println( e );
}
panel.setBorder( new TitledBorder( titulo ) );
return( panel );
}
- JMenuBar. Es la barra de menú principal. Una barra horizontal alargada en la que se colocarán las distintas opciones. Si miras en tu navegador, arriba, verás una barra de estas con opciones como "Archivo", "Editar", etc.
- JMenu. Es una de las cosas que se pueden añadir a un JMenuBar o a otro JMenu. Cuando añadimos uno de estos, tendremos un algo que al pinchar despliega un nuevo menú. Si en tu navegador, arriba donde pone "Archivo" pinchas con el ratón, verás que se despliega un menú con más opciones como "Abrir", "Guardar como", etc. Este "Archivo" si estuviera hecho en java sería un JMenu, ya que al pincharlo no hace nada, sólo despliega otro menú. Si añades un JMenu dentro de otro, tendrás un nuevo submenú que se despliega. Por ejemplo, si miras abajo en tu windows, en el botón de "Inicio" de abajo a la izquierda, lo pinchas y sale un menú. Ese "Inicio" sería un JMenu si estuviese hecho en java. En las opciones que despliega, ves que "Programas" tiene una flechita a la deracha. Poniendo ahí el ratón sale otro nuevo menú. Eso quiere decir que "Programas" también sería un JMenu que está dentro de JMenu "Inicio".
- JMenuItem. Por fin, este es el currito. Es el que cuando lo pinchas hace algo útil, como "guardar como", "abrir", etc.
- JSeparator. Este sólo sirve para poner una rayita y separar varios JMenuItem. Por ejemplo, dentro de "Editar", las opciones "Copiar", "Cortar" y "Pegar" suelen estar separadas con rayitas de otras opciones en el mismo menú. Estos son los JSeparator.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
public class java1407 extends JPanel {
public java1407() {
setLayout( new GridLayout( 2,1 ) );
JList lista = new JList( java1406.ids );
add( new JScrollPane( lista ) );
JComboBox combo = new JComboBox();
for( int i=0; i < 100; i++ )
combo.addItem( Integer.toString( i ) );
add( combo );
}
public static void main( String args[] ) {
java1407 lista = new java1407();
JFrame ventana = new JFrame();
ventana.getContentPane().add( lista,BorderLayout.CENTER );
ventana.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ) {
System.exit( 0 );
}
} );
ventana.setSize( 200,200 );
ventana.setTitle( "Tutorial de Java, Swing" );
ventana.setVisible( true );
}
}
La imagen siguiente es el resultado que se obtiene en pantalla tras la ejecución del ejemplo, y después de haber seleccionado uno de los elementos en la caja combo y abrirla para proseguir la selección de otra de las opciones o elementos que se permite elegir.
Una cosa que se ha mantenido con respecto a las listas de antes es que los objetos JList no proporcionan automáticamente la posibilidad de scroll o desplazamiento del contenido, que es una cosa que se espera que haga automáticamente, y resulta un poco chocante. No obstante, el añadir scroll a listas es sumamente sencillo, ya que es suficiente con incluir la JList en un JScrollPane, y todos los detalles del desplazamiento del contenido serán ya manejados bajo la responsabilidad del sistema.
Aunque lo más frecuente es que cada elemento seleccionable de una lista sea una etiqueta, Swing proporciona al componente JList también la posibilidad de presentar gráficos, con o sin texto asociado, y también proporciona un control adicional de eventos para adecuarse a los que se producen en la manipulación de este tipo de Componentes. Es decir, que en una lista también se pueden incluir instancias de clases como JButton, JTextField, JCheckBox, e incluso JTextArea, que es un componente multilínea.
En el ejemplo java1408.java se muestra precisamente una lista en la que se utilizan instancias de la clase JTextArea, para mostrar los valores que se cargan en la lista, que corresponden a un extracto del índice del Tutorial:
"Capitulo 4\nIntroduccion al Lenguaje Java",
"Capitulo 5\nConceptos Basicos de Java",
"Capitulo 6\nProgramas Basicos en Java",
"Capitulo 7\nEl Depurador de Java",
"Capitulo 8\nClases Java",
"Capitulo 9\nExcepciones en Java"
Cada valor incluye el carácter de nueva línea, \n, para forzar el salto de línea en medio del texto.
class MiRendererDeLista extends JTextArea implements ListCellRenderer {
public Component getListCellRendererComponent(
JList lista,Object valor,int indice,
boolean seleccionado, boolean conFoco ) {
setBorder( new BevelBorder( BevelBorder.RAISED ) );
// Presenta el text correspondiente al item
setText( valor.toString() );
// Pinta en los colores indicados y con la fuente seleccionada...
if( seleccionado ) {
// .. en el caso de un item marcado (rojo/blanco)
setBackground( Color.red );
setForeground( Color.white );
}
else {
// .. en el caso de un item no marcado (gris/negro)
setBackground( Color.lightGray );
setForeground( Color.black );
}
return( this );
}
}
El código es bastante simple, y la parte más interesante es la correspondiente a la clase anidada MiRendererDeLista, reproducido antes, que implementa un controlador diferente para cada celda de la lista, extendiendo en este caso a JTextArea en lugar de JLabel, como suele ser habitual. El resultado de la ejecución del ejemplo es el que muestra la figura.
Aunque el componente JTextArea también tiene sus limitaciones, como son el no permitir el uso de gráficos, se puede observar que las posibilidades que se presentan al programador se han visto tremendamente incrementadas con la inclusión de este tipo de Componente y con las nuevas características que proporciona Swing. En este caso, incluso es posible hacer que la altura de la celda esté recortada, en el caso de utilizar fuentes de caracteres muy grandes, debido a que la altura de cada uno de los elementos seleccionables de la lista se determina en el momento en que son construidos.
Si se echa un vistazo a los constructores de la clase JLabel, se puede observar claramente que Swing ofrece un API mucho más rico, presentando constructores con habilidades no disponibles en el AWT. El ejemplo java1403.java, crea varias instancias de la clase JLabel utilizando algunas de las características que permite Swing, como por ejemplo la utilización de gráficos, que resulta extremadamente simple.
import java.awt.*;
import java.awt.event.*;
import com.sun.java.swing.*;
class java1403 extends JPanel {
public java1403() {
setLayout( new GridLayout( 2,2 ) );
JLabel etiq1 = new JLabel();
etiq1.setText( "Etiqueta1" );
add( etiq1 );
JLabel etiq2 = new JLabel( "Etiqueta2" );
etiq2.setFont( new Font( "Helvetica", Font.BOLD, 18 ) );
add( etiq2 );
Icon imagen = new ImageIcon( "star0.gif" );
JLabel etiq3 = new JLabel( "Etiqueta3", imagen,SwingConstants.CENTER );
etiq3.setVerticalTextPosition( SwingConstants.TOP );
add( etiq3 );
JLabel etiq4 = new JLabel( "Etiqueta4",SwingConstants.RIGHT );
add( etiq4 );
}
public static void main( String args[] ) {
JFrame ventana = new JFrame( "Tutorial de Java, Swing" );
ventana.addWindowListener( new WindowAdapter() {
public void windowClosing( WindowEvent evt ){
System.exit( 0 );
}
} );
ventana.getContentPane().add( new java1403(),BorderLayout.CENTER );
ventana.setSize( 300,150 );
ventana.setVisible( true );
}
}
La figura siguiente es el resultado de la ejecución del programa anterior, donde se puede observar que en la Etiqueta2 se muestra el cambio de fuente de caracteres y en la Etiqueta3 se incluye una imagen. En este último caso, el tamaño de la imagen es el que determina el tamaño mínimo de la etiqueta.
El tipo de letra con que se presenta el texto de la etiqueta se puede cambiar fácilmente, basta con crear una nueva fuente de caracteres e invocar al método setFont() de la clase JLabel para que el cambio surta efecto. La fuente de caracteres puede ser cualquiera de las estándar, dentro de los tamaños soportados por la máquina virtual Java de la plataforma. El control de la fuente de caracteres utilizada para la etiqueta se puede realizar con una línea de código semejante a la siguiente:
label.setFont( new Font( "Dialog",Font.PLAIN,12 ) );
Los colores del texto y del fondo de la etiqueta también se pueden cambiar de forma muy sencilla, mediante la invocación de los métodos setForeground() y setBackground().
J COMBOBOX:
JComboBox, es un componente swing, y como tal, podemos crear nuestro propio modelo de datos al momento de crear y manipular a este componente(en este caso: jComboBox).
En este caso, el ejercicio intenta mostrar la forma sencilla al momento de implementar nuestro propio Modelo de datos para un componente JComboBox.
El ejercicio consiste, en una tipica “barra de direcciones de un navegador”, ingresas la direccion, entras a la pagina, luego el navegador comprueba si existe la direccion,en el caso de no existir, agrega la direccion de la pagina a la barra de direcciones, para un posterior facil acceso.
Bien, para este ejercicio implementaremos 3 clase. la vista(WindowDemoEditaCombo), el control(ControlDemoEditaCombo), y el Modelo del JComboBox (ModeloCombo).
WindowDemoEditaCombo, esta es la clase, que dibuja los componentes swing; En este caso para crear un JComboBox, necesario primero crear nuestro modelo, el cual recibe una cadena de caracteres, los mismos que seran mostrados como items en el combo.
setExtendedState()
el estado en que queremos que aparezca al realizarle un setVisible(true)
.
Para ello utilizamos la constante JFrame.MAXIMIZED_BOTH
de la siguiente forma:
- import javax.swing.JFrame;
- public class MaximizarJFrame{
- public static void main(String[] args) {
- final JFrame frame = new JFrame("Prueba JFrame");
- frame.setExtendedState(JFrame.MAXIMIZED_BOTH);
- frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE);
- frame.setVisible(true);
- }
- }
import javax.swing.JFrame; public class MaximizarJFrame{ public static void main(String[] args) { final JFrame frame = new JFrame("Prueba JFrame"); frame.setExtendedState(JFrame.MAXIMIZED_BOTH); frame.setDefaultCloseOperation(frame.EXIT_ON_CLOSE); frame.setVisible(true); } }
además podemos indicarle otras opciones:
- JFrame.NORMAL: Inicializa el JFrame en estado Normal
- JFrame.ICONIFIED: Inicializa el JFrame en estado Minimizado.
- JFrame.MAXIMIZED_HORIZ: Inicializa el JFrame en estado Maximizado Horizontalmente
- JFrame.MAXIMIZED_VERT: Inicializa el JFrame en estado Maximizado Verticalmente
- JFrame.MAXIMIZED_BOTH: Inicializa el JFrame en estado Maximizado en ambos sentidos