Tamaño de ventanas y componentes en Java

De ChuWiki

Igual que manejando bien los layouts no es necesario dedicarse a colocar los componentes java, los métodos para asignar tamaños estilo setSize(), setBounds(), etc, además de inútiles, no suelen ser necesarios.


Tamaño de los componentes simples[editar]

Los componentes simples, estilo JLabel, JButton, JTextField, etc saben todos cual es su tamaño adecuado para mostrar la información que contienen. El método getPreferredSize() de cada uno de ellos devuelve el tamaño que deberían tener para mostrar correctamente el icono, el texto o lo que sea que tengan que presentar.

Los JTextField y demás componentes de texto son un caso especial, puesto que su método getPreferredSize(), al igual que el de los demás componentes, devuelve el tamaño necesario para visualizar el texto que llevan dentro. Si el componente está vacio, devolveran un ancho de cero (o casi). Para que tengan un tamaño adecuado aunque estén vacios, conviene usar algún constructor especial o llamar al método setPreferredSize().

// Este constructor hace que el JTextField tenga el tamaño mínimo para presentar 10 caracteres.
JTextField texto = new JTextField(10);

El Canvas de dibujo también es un caso especial. Puesto que para dibujar en condiciones es necesario heredar de él, lo mejor es redefinir el método getPreferredSize() para que nos devuelva el tamaño que deseemos.

public class Lienzo extends Canvas
{
   public Dimension getPreferredSize()
   {
      return new Dimension(ancho, alto);
   }
   public void paint (Graphics g)
   {
      // Aquí el código de dibujo.
   }
}

Tamaño de los contenedores[editar]

Los contenedores java, estilo JPanel, JScrollPane, etc, también tienen su getPreferredSize(). Los contenedores deciden su tamaño en función del layout y de los componentes que tienen dentro.

Por ejemplo, supongamos un JPanel que tiene un FlowLayout y varios botones. El FlowLayout hace que esos botones se coloquen en fila horizontal dentro del JPanel. El método getPreferredSize() del JPanel pregunta a cada botón su getPreferredSize(), suma todos los anchos y devuelve su getPreferredSize() como el más alto de los botones y la suma del ancho de todos ellos. Es decir, el tamaño necesario para que todos los botones se vean como deben verse.

Por supuesto, si fijamos un setLayout(null), lo hemos fastidiado. El tamaño preferido de este panel será 0,0

Cuando alguien fija el tamaño al JPanel, este va llamando a los métodos setBounds() de cada botón, para ponerlos en su posición y darles el tamaño. Esto hace totalmente inútil llamar desde fuera a los setBounds() de los botones y etiquetas, puesto que el panel también llamará a estos métodos y machacará el tamaño que hayamos dado previamente.

En resumen, el getPreferredSize() de un contenedor devuelve el tamaño necesario para que todo lo que tiene dentro se vea bien. Cuando alguien llama al setSize() o setBounds() del contenedor, este se encarga de llamar a los setBounds() de cada componente.


Tamaño de las ventanas[editar]

Los JFrame, JDialog y demás son especiales. Tienen todo lo de los demás, como getPreferredSize() y demás, pero la diferencia esencial es que no van dentro de ningún contenedor, por lo que nadie llamará nunca (o casi) automáticamente a sus métodos setSize(), setBounds(), etc.

En general, si nosotros visualizamos una ventana y llamamos a setSize() o setBounds(), esta llamará a los métodos setSize() o setBounds() de sus paneles internos y estos a su vez a los de sus componentes. La llamada a un setSize() o setBounds() de una ventana, anula todas las llamadas previas que hayamos hecho a setSize() o setBounds() de los demás contenedores o componentes.

El método fetén es llamar al método pack() del JFrame o JDialog. Este método llama al getPreferredSize() de los componentes internos y hace que la ventana coja el tamaño justo para visualizarlo todo bien.

En resumen[editar]

Para que las ventanas con todos sus componentes nos salgan de tamaños adecuados, incluso redimensionando la ventana, debemos tener en cuenta lo siguiente:

  • No poner nunca layouts null y elegir un layout adecuado.
  • Es inútil llamar a setSize() y setBounds() con excepción de los JFrame y JDialog
  • Algunos componentes como Canvas o campos de texto necesitan una ayuda para su tamaño adecuado. Hay que redefinir el método getPreferredSize() o llamar a setPreferredSize(). Aun así esto no es garantía de que se respete el tamaño.
  • Usar el método pack() de los JFrame y JDialog, en vez de dar un setSize() o setBounds() a pelo.