Construcción de formularios Swing con BoxFormBuilder


Introducción


BoxFormBuilder es una clase de ayuda para la construcción de formularios Swing. La construcción de interfaces de usuario Swing suele plantear problemas de aspecto visual difíciles de resolver, dando lugar a un código bastante engorroso tanto si se programan manualmente, como si se utiliza un editor de formularios gráfico.

BoxFormBuilder permite crear formularios con aspecto profesional, que soportan bien cambios de tamaño con un código simple y claro.

BoxFormBuilder utiliza exclusivamente BoxLayouts para la construcción de formularios.

BoxFormBuilder está en la librería jdal-swing desde la versión 1.0, pero ha evolucionado en dos clases en la versión de desarrollo actual (1.3.1). La clase SimpleBoxFormBuilder que deriva directamente del BoxFormBuilder original y permite la creación de formularios simples y el nuevo BoxFormBuilder que permite creación de componentes complejos mediante la anidación de componentes simples.



SimpleBoxFormBuilder


SimpleBoxFormBuilder construye las interfaces de usuario Swing mediante la repetición de un patrón básico formado por la unión de un HorizontalBox y varios VerticalBox para crear una estructura tabular. SimpleBoxFormBuilder añade componentes a esta estructura mediante el uso de un cursor implícito.

Los componentes Swing se añaden al formulario mediante los métodos add(Component c) para componentes individuales o addComponent(String label, Component c) para incluir al mismo tiempo un JLabel y un componente. El componente se añade al lugar apuntado por un cursor interno de SimpleBoxFormBuilder y se incrementa automáticamente en las llamadas a los métodos add. Para cambiar de columna se utiliza el método row() que permite especificar la altura máxima que tendrá la fila que se va a añadir. El valor por defecto es de 25 puntos. Es posible que tenga que ajustar este valor dependiendo del Look and Feel que esté utilizando.



BoxFormBuilder


En la figura anterior, el lugar de color amarillo, puede ser ocupado directamente por un componente Swing o por un nuevo patrón básico creado por un nuevo SimpleBoxFormBuilder. Este modelo de composición da lugar a un sistema bastante flexible que prácticamente cubre la totalidad de las distribuciones de componentes usuales en las interfaces gráficas de usuario.

BoxFormBuilder añade los métodos startBox() y endBox() a la clase SimpleBoxFormBuilder para permitir añadir un nuevo componente en el lugar apuntado por el cursor interno. A partir de la llamada a startBox() las llamadas siguientes a los métodos add() y row() se redirigen a una nueva instancia de SimpleBoxFormBuilder. El método endBox añade el resultado y restituye el builder original.

La figura de la izquierda muestra la distribución de componentes de un formulario formado por un Combo, tres JTextFields precedidos de etiquetas y un JTexArea. Le recomiendo que antes de comenzar la creación de un formulario con BoxFormBuilder haga un pequeño dibujo en un papel identificando claramente los componentes básicos de los que está compuesto. En este caso se trata de tres componentes básicos distribuidos en una sola columna. Las dos primeras filas, que contienen el Combo y los JTextFields tendrán una altura fija. La última fila, que contiene el área de texto tendrá un tamaño variable en función del tamaño del componente que contenga el formulario. Es decir, al cambiar el tamaño del formulario todo el espacio extra irá a parar al área de texto.

El método setDebug(boolean debug) muestra los bordes de los BoxLayouts que se utilizan en la construcción del formulario y es útil durante la construcción del mismo. Finalmente el método setFixedHeight(boolean fixed) permite restringir la altura de los componentes. creados en el método startBox().


A continuación se muestra el código para construir el formulario.

/**
 * Sample for BoxFormBuilder
 *
 * @author Jose Luis Martin
 */
public class SampleForm extends JDialog {
 
	private JComboBox sex = new JComboBox();
	private JTextField name = new JTextField();
	private JTextField surname = new JTextField();
	private JTextField secondSurname = new JTextField();
	private JTextArea description = new JTextArea();
 
	public SampleForm() {
		this.add(build());
	}
 
	private JComponent build() {
		// create a box form builder and set a titled border in the created component.
		BoxFormBuilder fb = new BoxFormBuilder(BorderFactory.createTitledBorder(("Sample")));
		fb.row();                       // start a new base component row
		fb.startBox();                  // add new simple box     
		fb.setFixedHeight(true);        // fix the height of this simple box
		fb.row();                       // add row, now in the simple box.
		fb.add(sex);                    // add the sex combo;
		fb.endBox();  					// end the simpleBox;
		fb.row();                       // add new row in base component.
		fb.startBox();                  // add new simpleBox
		fb.setFixedHeight(true);        // fix the height of this simple box
		fb.row();                       // add new row in the new simpleBox
		fb.add("Nombre: ", name);       // add the name text box (this call increment the cursor by two).
		fb.row();                       // start a new simple box row
		fb.add("Primer Apellido: ", surname);  // add the first surname text box
		fb.row();                       // start a new simple box row
		fb.add("Segundo Apellido: ", secondSurname);
		fb.endBox();                    // end simple box
		fb.row();                       // new base component row
		fb.startBox();                  // start a new simple box (note that don't have a fixed height)
		fb.row();                       // new simple box  row
		fb.add(FormUtils.newLabelForBox("Descripción"));
		fb.row();                       // new simpleBox row
		fb.setHeight(Short.MAX_VALUE);  // let this row to be as bigger as it can.
		fb.add(new JScrollPane(description));  // add the text area
		fb.endBox();                    // end last simple box
 
		// build the form  return the JComponent.
		return fb.getForm();
	}
 
	public static void main(String[] args) {
		ApplicationContextGuiFactory.setPlasticLookAndFeel();
		SampleForm dlg = new SampleForm();
		dlg.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
		dlg.setSize(400, 300);
		dlg.setVisible(true);
	}
}

Por último, el resultado del código de ejemplo anterior: