Un tutorial sobre este interesante Layout de Swing.
Vamos examinar este Layout de Swing a través de un ejemplo en el que construiremos un formulario. Empezaremos con algo sencillo: hemos usado setLayout(...) para asignarle al contenedor raíz el BoxLyout. Obtenemos el tamaño del applet para visualizarlo en los JTextField. No hemos especificado tamaño para los componentes, a pesar de ello, los JLabel y los JButton adoptan el tamaño adecuado para que se muestre su texto. A continuación una imagen del applet:
El resultado no es precisamente vistoso. Su código:
package boxlayout_applet;
import java.awt.*;
import javax.swing.*;
public class MiApplet extends JApplet {
//// Etiquetas (justificado a la izquierda), textos y botones
JLabel etiAncho = new JLabel( "Ancho:", SwingConstants.LEFT );
JTextField txtAncho = new JTextField();
JLabel etiAlto = new JLabel( "Alto:", SwingConstants.LEFT );
JTextField txtAlto = new JTextField();
JButton btnBoton1 = new JButton( "Botón 1" );
//Initialize the applet
public void init() {
try {
//// Obtenemos tamaño del applet
int anchoApplet = this.getWidth();
int altoApplet = this.getHeight();
//// Contenedor raiz: BoxLayout
Container contRaiz = getContentPane();
contRaiz.setLayout( new BoxLayout( contRaiz, BoxLayout.PAGE_AXIS));
contRaiz.setBackground( Color.cyan);
//// Introduzco ancho y alto de applet en los campos
txtAncho.setText( String.valueOf( anchoApplet));
txtAlto.setText( String.valueOf( altoApplet));
//// Añado subpaneles y botón al panel raiz
contRaiz.add( etiAncho );
contRaiz.add( txtAncho );
contRaiz.add( etiAlto );
contRaiz.add( txtAlto );
contRaiz.add( btnBoton1 );
}
catch(Exception e) {
e.printStackTrace();
}
}
}
Observar que el constructor del BoxLayout exige dos argumentos, el primero es el contenedor al que se asigna. El segundo es la orientación general:
Dos ideas para empezar:
El siguiente paso será:
txtAncho.setHorizontalAlignment( JTextField.RIGHT); txtAlto.setHorizontalAlignment( JTextField.RIGHT);
private void setTamaño( JComponent comp, int x, int y ) {
Dimension tam = new Dimension( x, y );
comp.setMaximumSize( tam );
comp.setPreferredSize( tam );
}
De esta forma podemos determinar el tamaño de cada campo:
setTamaño( txtAncho, 80,20); setTamaño( txtAlto, 80,20);
contRaiz.add( txtAlto ); contRaiz.add( Box.createVerticalGlue()); contRaiz.add( btnBoton1 );
El aspecto resultante es:
Ha mejorado, pero todavía podemos refinarlo para dar un aspecto de formulario, donde las etiquetas aparezcan a la izquierda y en la misma línea que su correspondiente campo de texto. Para ello nos ayudaremos de subpaneles. Dejar un interfaz adecuado no depende sólo de conocer los Layouts, también es necesario anidar paneles. En nuestro caso, haremos que cada par JLabel-JTextField este contenido en un subpanel. Por ejemplo, etiAncho y txtAncho se añaden a un subpanel denominado pnlAncho, que justifica sus componentes a la izquierda:
//// Añado etiquetas y campos a subpaneles
JPanel pnlAncho = new JPanel(); // Subpanel del ancho
pnlAncho.setLayout( new FlowLayout(FlowLayout.LEFT));
pnlAncho.add( etiAncho );
pnlAncho.add( txtAncho );
Además, para que todas las etiquetas tengan el mismo ancho les aplico setTamaño(). El código de init() ha quedado así:
public void init() {
try {
//// Obtenemos tamaño del applet
int anchoApplet = this.getWidth();
int altoApplet = this.getHeight();
//// Contenedor raiz: BoxLayout
Container contRaiz = getContentPane();
contRaiz.setLayout( new BoxLayout( contRaiz, BoxLayout.PAGE_AXIS));
contRaiz.setBackground( Color.cyan);
//// Introduzco ancho y alto de applet en los campos
txtAncho.setText( String.valueOf( anchoApplet));
txtAlto.setText( String.valueOf( altoApplet));
//// El texto se alinea a la derecha
txtAncho.setHorizontalAlignment( JTextField.RIGHT);
txtAlto.setHorizontalAlignment( JTextField.RIGHT);
//// Indico tamaño
setTamaño( etiAncho, 40,20);
setTamaño( txtAncho, 80,20);
setTamaño( etiAlto, 40,20);
setTamaño( txtAlto, 80,20);
//// Añado etiquetas y campos a subpaneles
JPanel pnlAncho = new JPanel(); // Subpanel del ancho
pnlAncho.setLayout( new FlowLayout(FlowLayout.LEFT));
pnlAncho.setBackground( Color.BLUE);
pnlAncho.add( etiAncho );
pnlAncho.add( txtAncho );
JPanel pnlAlto = new JPanel(); // Subpanel de la altura
pnlAlto.setLayout( new FlowLayout(FlowLayout.LEFT));
pnlAlto.setBackground( Color.GREEN);
pnlAlto.add( etiAlto );
pnlAlto.add( txtAlto );
btnBoton1.setAlignmentX( Component.CENTER_ALIGNMENT );
//// Añado subpaneles y botón al panel raiz
contRaiz.add( pnlAncho );
contRaiz.add( pnlAlto );
contRaiz.add( Box.createVerticalGlue());
contRaiz.add( btnBoton1 );
}
catch(Exception e) {
e.printStackTrace();
}
}
Observar que el botón lo hemos alineado hacia el centro, por medio de setAlignmentX( Component.CENTER_ALIGNMENT )con lo que aunque hagamos más ancho el applet siempre se mantendrá centrado. La imagen del resultado es la siguiente:
Podemos observar que nos volvemos a encontrar con el fenomeno de expansión automática: no hemos determinado el tamaño de los subpaneles, con lo que se expanden sobre el panel raiz, ocupando más altura de la necesaria. Esto tiene una solución sencilla con setPreferredSize(). Esta forma de determinar tamaño es normalmente flexible: el subpanel adapta su tamaño al aumento del tamaño del panel padre:
pnlAncho.setPreferredSize( new Dimension( anchoApplet, 24)); pnlAlto.setPreferredSize( new Dimension( anchoApplet, 24));
Existe otra forma de componente invisible que puede ser de utilidad: Box.createRigidArea(new Dimension(ancho, alto)). Este método inserta un componente invisible con el tamaño especificado. Nos permite separar componentes o subpaneles de un BoxLayout. Si a nuestro ejemplo anterior le añadimos un segundo y tercer botón, aparecerán juntos. Gracias a este método tienen un espacio de saparación:
contRaiz.add( btnBoton1 ); contRaiz.add( Box.createRigidArea(new Dimension(3,3) )); contRaiz.add( btnBoton2 ); contRaiz.add( Box.createRigidArea(new Dimension(3,3) )); contRaiz.add( btnBoton3 );
El resultado final aparece a continuación. No es un error, se ha hecho a proposito: el botón 3 no tiene espacio suficiente. Los componentes que no caben no aparecen: