Skip to content

4 Layouts

Paneles

La clase Panel es la clase más simple de los contenedores de componentes gráficos. Su uso permite que las aplicaciones puedan usar multiples layouts. Permite que cada contenedor pueda tener su propio esquema de fuentes, colores, zona de diálogo, etc.

public class Panels {
    public void show() {
        Panel panel = new Panel();
        Button button = new Button("Panel button");

        Label label = new Label("Label text");

        panel.add(button);
        panel.add(label);

        Frame frame = new Frame("Mi panel");
        frame.add(panel);
        frame.setSize(1000, 1000);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new Panels().show();
    }
}

El método setLayout(layout) nos permite indicar de que forma se disponen los elementos.

Layouts manager

Los layouts managers o manejadores de composición permiten controlar la disposición de los diversos componentes dentro de un contenedor, es decir, especifican que distribución tendrán los componentes a la hora de colocarlos sobre un contenedor. Java dispone de varios como: BorderLayout, GridLayout, FlowLayout, CardLayout, GridBagLayout, etc.

¿Por qué Java proporciona estos esquemas predefinidos de disposición de componentes? La razón es simple: imaginemos que deseamos agrupar objetos de distinto tamaño en celdas de una rejilla virtual: si confiados en nuestro conocimiento de un sistema gráfico determinado, y codificamos a mano tal disposición, deberemos prever el redimensionamiento de la ventana, su repintado cuando sea cubierto por otra ventana, etc., además de todas las cuestiones relacionadas con un posible cambio de plataforma (uno nunca sabe a donde van a ir a parar nuestras ventanas).

Sigamos imaginando, ahora, que un hábil equipo de desarrollo ha previsto las disposiciones gráficas más usadas y ha creado un gestor para cada una de tales configuraciones, que se ocupará, de forma transparente para nosotros, de todas esas cuitas de formatos. Bien, pues estos gestores son instancias de las distintas clases derivadas de Layout Manager y que se utilizan en los contenedores de nuestras aplicaciones.

Los Layouts liberan al programador de tener que preocuparse de dónde ubicar cada uno de los componentes cuando una ventana es redimensionada o cuando una ventana es refrescada o cuando una ventana es llevada a una plataforma que maneja un sistema de coordenadas diferente.

FlowLayout

Es el layout más simple y el que se utiliza por defecto en los paneles. Los componentes añadidos se encadenan en forma de lista horizontal, de izquierda a derecha.

FlowLayout

Figura 11 - FlowLayout

Existen varias formas de crear un FlowLayout:

  • FlowLayout(int align, int hgap, int vgap): Crea un FlowLayout especificando el alineamiento de los elementos, y el espaciado horizontal (hgap) y vertical (vgap). El valor del align puede ser: - 0 para la izquierda (se puede usar la constante LEFT). - 1 para centrado (se puede usar la constante CENTRE). - 2 para la derecha (se puede usar la constante RIGHT) - 3 para posicionarse al principio del elemento. Esto depende de la orientación del componente si estamos ante una disposición de izquierda a derecha se posicionaran a la izquierda, si no a la derecha. Se puede usar la constante LEADING. - 4 para posicionarse al final del elemento. Esto depende de la orientación del componente si estamos ante una disposición de izquierda a derecha se posicionará a la derecha, si no a la izquierda. Se puede usar la constante TRAILING.
  • FlowLayout(int align): Crea un FlowLayout con el alineamiento especificado, y con un espacio por defecto de 5, tanto vertical como horizontal.
  • FlowLayout(): Crea una FlowLayout centrado y con espaciado vertical y horizontal de 5, por defecto.

Existen también los getters y setters de dichas propiedades. Además del método setAlignOnBaseline(boolean b) que permite alinear los elementos según su baseline.

public class FlowLayouts {
    public void show() {

        Frame frame = new Frame();
        Panel panel = new Panel();
        LayoutManager flowLayout = new FlowLayout(FlowLayout.CENTER, 10, 10);

        Component button = new Button("Button");
        Component other = new Button("Other");
        Component third = new Button("third");

        panel.setLayout(flowLayout);
        panel.add(button);
        panel.add(other);
        panel.add(third);

        frame.setSize(1000, 1000);
        frame.add(panel);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new FlowLayouts().show();
    }
}

BorderLayout

La composición BorderLayout proporciona un esquema más complejo de colocación de los componente en un panel. La composición utiliza cinco zonas para colocar los componentes sobre ellas: norte, sur, este, oeste y centro.

BorderLayout

Figura 12 - BorderLayout

Para poder añadir cada componente, en alguna de dichas direcciones se debe usar la sobrecarga del método add(String name, Component component), siendo el valor de name el nombre de la posición del elemento.

Se puede usar indicar el espacio vertical y horizontal haciendo uso del constructor que los recoge: BorderLayout(int vgap, int hgap); o con los setters necesarios: setVgap() para vertical y setHgap() para horizontal.

public class BorderLayouts {

    public void show(){
        Frame frame = new Frame();
        Panel panel = new Panel();
        LayoutManager borderLayout = new BorderLayout();

        Button button1 = new Button("North");
        Button button2 = new Button("South");
        Button button3 = new Button("West");
        Button button4 = new Button("East");
        Button button5 = new Button("Center");

        panel.setLayout(borderLayout);

        panel.add("North", button1);
        panel.add("South", button2);
        panel.add("West", button3);
        panel.add("East", button4);
        panel.add("Center", button5);

        frame.add(panel);
        frame.setSize(1000, 500);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new BorderLayouts().show();
    }

}

GridLayout

La composición GridLayout proporciona una gran flexibilidad para situar componentes. El layout crea con un número de filas y columnas y los componentes van dentro de las celdas de la tabla así definida.

Todos los componentes comprendido en el layout tienen el mismo tamaño. Si el número de filas es menor que el número de componentes a añadir, omite el valor dado para el número de columna y añade las columnas necesarias para abarcar el número de componentes.

GridLayout

Figura 13 - GridLayout

El constructor tiene varias sobrecargas:

  • GridLayout(int rows, int cols, hgap, vgap): crea un GridLayout definiendo el número de filas y columnas, así como el espaciado vertical y horizontal. El número de filas o el de columnas no puede ser 0 (se lanza un IllegalArgumentException), aunque uno de ellos sí.
  • GridLayout(int rows, int cols): Crea un GridLayout con el número de filas y columnas. Por defecto, el espaciado, tanto horizontal como vertical, queda en 0.
  • GridLayout(): Crea un GridLayout con una fila y ninguna columna.
public class GridLayouts {
    public void show() {
        Frame frame = new Frame();
        Panel panel = new Panel();
        LayoutManager borderLayout = new GridLayout(3, 2);

        Button button1 = new Button("1");
        Button button2 = new Button("2");
        Button button3 = new Button("3");
        Button button4 = new Button("4");
        Button button5 = new Button("5");
        Button button6 = new Button("6");

        panel.setLayout(borderLayout);

        panel.add(button1);
        panel.add(button2);
        panel.add(button3);
        panel.add(button4);
        panel.add(button5);
        panel.add(button6);

        frame.add(panel);
        frame.setSize(1000, 500);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new GridLayouts().show();
    }
}

CardLayout

Este tipo de composición es usado cuando se necesita una zona de la ventaja que permita colocar distintos componentes en cada momento. Este layout suele ir asociado con un Choice, de tal modo que cada selección determina el panel que se presentará.

public class CardLayouts {

    private final static String PANEL_BUTTON = "Panel con botones";
    private final static String PANEL_TEXT = "Panel con campo de texto";
    public void show() {
        Frame frame = new Frame();
        Panel parent = new Panel();
        Panel card = new Panel();
        Panel panel = new Panel();

        LayoutManager borderLayout = new BorderLayout();
        LayoutManager cardLayout = new CardLayout();

        Choice choice = new Choice();

        choice.addItem(PANEL_BUTTON);
        choice.addItem(PANEL_TEXT);

        panel.add(choice);

        parent.setLayout(borderLayout);
        parent.add("North", panel);

        card.setLayout(cardLayout);

        Panel child1 = new Panel();
        child1.add(new Button("Button 1"));
        child1.add(new Button("Button 2"));
        child1.add(new Button("Button 3"));

        Panel child2 = new Panel();
        child2.add(new TextField("Texto", 20));

        card.add(PANEL_BUTTON, child1);
        card.add(PANEL_TEXT, child2);

        parent.add("Center", card);


        new CardLayout().show(card,  PANEL_TEXT);
        new CardLayout().show(card, PANEL_BUTTON);


        frame.add(parent);
        frame.setSize(1000, 500);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new CardLayouts().show();
    }
}

De esta manera, puede pasar de esto:

CardLayout1

Figura 14 - CardLayout1

A esto:

CardLayout2

Figura 15 - CardLayout2

Layout personalizado

Para poder crear un layout personalizada es necesario implementar la interfaz LayoutManager y sobrescribir sus métodos:

  • void addLayoutComponent(String name, Component component). Añade el componente a la posición nombrada.
  • void removeLayoutComponent(Component component). Elimina el componente del layout.
  • Dimension preferredLayoutSize(Container parent). Calcula el tamaño preferido para el especificado container.
  • Dimension miniumLayoutSize(Container parent). Calcula el tamaño mínimo para el especificado container.
  • void layoutContainer(Container parent). Establece el especificado container.

En el siguiente ejemplo, se desarrolla un layout que permite colocar los componentes en posiciones absolutas del panel que contenga a este layout:

CustomLayout

Figura 16 - CustomLayout

public class CustomLayout implements LayoutManager {
    @Override
    public void addLayoutComponent(String name, Component comp) {

    }

    @Override
    public void removeLayoutComponent(Component comp) {

    }

    @Override
    public Dimension preferredLayoutSize(Container parent) {
        Insets insets = parent.getInsets();
        int num = parent.getComponentCount();
        int width = 0;
        int height = 0;

        for (int i = 0; i < num; i++) {
            Component component = parent.getComponent(i);
            Dimension d = component.getPreferredSize();
            Point p = component.getLocation();

            if((p.x + d.width) > width){
                width = p.x + d.width;
            }

            if((p.y + d.height) > height){
                height = p.y + d.height;
            }
        }
        return new Dimension(insets.left + insets.right + width, insets.top + insets.bottom + height);
    }

    @Override
    public Dimension minimumLayoutSize(Container parent) {
        return preferredLayoutSize(parent);
    }

    @Override
    public void layoutContainer(Container parent) {
        int num = parent.getComponentCount();

        for (int i = 0; i < num; i++) {
            Component component = parent.getComponent(i);
            Dimension d = component.getPreferredSize();
            component.setSize(d.width, d.height);
        }
    }
}
public class CustomLayouts {
    public void show() {
        Frame frame = new Frame();
        Panel panel = new Panel();
        Button button1 = new Button("Aceptar");
        Button button2 = new Button("Abrir");
        Button button3 = new Button("Cerrar");
        Label label = new Label("Texto");
        TextField textField = new TextField("", 20);

        panel.setLayout(new CustomLayout());

        panel.add(button1);
        panel.add(button2);
        panel.add(button3);
        panel.add(label);
        panel.add(textField);

        button1.setLocation(0, 10);
        button2.setLocation(70, 10);
        button3.setLocation(30, 40);
        label.setLocation(75,70);
        textField.setLocation(120, 70);

        frame.setSize(500, 500);
        frame.add(panel);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new CustomLayouts().show();
    }
}

Canvas

Un lienzo es una parte de nuestra UI donde se le permite a los usuarios realizar pintadas. La clase Canvas representa un lienzo y sus características principales son:

  • Permite dibujar directamente en el componente utilizando los métodos de la clase Graphic.
  • Puede manejar eventos del ratón y teclado para interactividad.
  • Se puede añadir contenedor de AWT como Frame o Panel, etc.

Canvas

Figura 17 - Canvas

public class CanvasExample {
    public void show() {
        Canvas canvas = new Canvas();

        Panel panel = new Panel();

        panel.add(canvas);

        Frame frame = new Frame();
        frame.add(panel);
        frame.setSize(500, 500);
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        new CanvasExample().show();
    }
}

Proyecto Layout

En el siguiente proyecto, se va a desarrollar una aplicación Ui como la siguiente:

Proyecto Layout

Figura 18 - Proyecto Layout

public class LayoutProject {

    private static class MyCanvas extends Canvas{
        @Override
        public void paint(Graphics g) {
            int w = getSize().width;
            int h = getSize().height;

            g.drawRect(0, 0, w-1, h-1);
            g.drawString("Canvas", (w-g.getFontMetrics().stringWidth("Canvas"))/2, 10);
        }
    }
    public void show() {
        Panel panel = createPanel();
        Frame frame = new Frame();

        frame.setSize(1000, 1000);
        frame.add(panel);
        frame.setVisible(true);
    }

    private Panel createPanel() {
        Panel panel = new Panel(); // Parent
        Panel start = new Panel(); // Left
        Panel end = new Panel(); // Right
        Panel buttons = new Panel(); // Buttons panel
        Panel canvasPanel = new Panel();

        start.setLayout(new BorderLayout());
        end.setLayout(new BorderLayout());
        canvasPanel.setLayout(new BorderLayout());
        canvasPanel.setBounds(1, 1, 200, 20);

        printStart(start);
        printCenter(buttons);
        printCanva(canvasPanel);
        printEnd(end);

        start.add("East", buttons);
        start.add("South", canvasPanel);

        panel.add(start);
        panel.add(end);
        return panel;
    }

    private void printEnd(Panel panel) {
        Label label = new Label("Editor");
        TextArea textField = new TextArea("Aquí se puede escribir", 8, 30);

        panel.add("North", label);
        panel.add("South", textField);
    }

    private void printCenter(Panel panel) {
        Button deleteButton = new Button("Borrar");
        Button printButton = new Button("Imprimir");

        Choice figures = new Choice();
        figures.addItem("Cuadrado");
        figures.addItem("Circulo");
        figures.addItem("Triángulo");

        Checkbox checkbox = new Checkbox("Relleno");

        panel.add(deleteButton);
        panel.add(printButton);
        panel.add(figures);
        panel.add(checkbox);
    }

    private void printCanva(Panel panel) {
        Label pencilLabel = new Label("Lápiz");
        TextField textField = new TextField("1", 8);
        Scrollbar pencilScrollbar = new Scrollbar(Scrollbar.HORIZONTAL, 1, 1, 1,  10);
        pencilScrollbar.setBounds(1, 1, 100, 5);

        panel.add("North", pencilLabel);
        panel.add("East", textField);
        panel.add("Center", pencilScrollbar);
    }

    private void printStart(Panel panel) {
        List colors = new List(6, false);

        colors.add("Rojo");
        colors.add("Naranja");
        colors.add("Amarillo");
        colors.add("Verde");
        colors.add("Azul");
        colors.add("Morado");
        colors.add("Negro");
        colors.add("Blanco");

        panel.add("West", colors);

        Canvas canvas = new MyCanvas();
        canvas.setBounds(0,0, 100, 100);
        panel.add("Center", canvas);
    }

    public static void main(String[] args) {
        new LayoutProject().show();
    }
}