martes, 29 de marzo de 2011

Investigar sobre los controles JTable y JTree. Desarrollar un ejemplo utilizando los controles

JTable
Un JTable es un componente visual de java que nos permite dibujar una tabla, de forma que en cada fila/columna de la tabla podamos poner el dato que queramos; un nombre, un apellido, una edad, un número, etc, etc.

Para utilizar tablas en java se puede usar JTable, este se utiliza para mostrar y organizar cierta información en tablas; encargándose JTable de la parte gráfica, y TableModel de la parte lógica. Junto con estos se pueden utilizar varios componentes que complementan y mejoran la calidad de visualización y orden de la tabla.
JTable brinda mucha facilidad, ya que tiene la capacidad de crear desde tablas básicas y muy sencillas, hasta tablas de alta complejidad de información y estructura.
En el programa creé dos tablas, la primera utilizando únicamente JTable, en cambio en la segunda utilicé TableModel, con estos ejemplos podrá notar la diferencia entre utilizar y no utilizar componentes.


Ejemplo:

import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.JTable;
import java.awt.Dimension;
import java.awt.GridLayout;
import java.awt.event.MouseAdapter;
import java.awt.event.MouseEvent;

public class SimpleTableDemo extends JPanel {

    private boolean DEBUG = true;

    public SimpleTableDemo() {
        super(new GridLayout(1, 0));

        //Definición de los Header de las columnas
        String[] columnNames = {"Nombre", "Apellido", "Direccion", "Telefono", "Correo"};

        //Definición de la información de las filas
        Object[][] data = {
            {"Mary", "Campione", "Snowboarding", new Integer(5), new Boolean(false)},
            {"Alison", "Huml", "Rowing", new Integer(3), new Boolean(true)},
            {"Kathy", "Walrath", "Knitting", new Integer(2), new Boolean(false)},
            {"Sharon", "Zakhour", "Speed reading", new Integer(20), new Boolean(true)},
            {"Philip", "Milne", "Pool", new Integer(10), new Boolean(false)}
        };

        final JTable table = new JTable(data, columnNames);
        table.setPreferredScrollableViewportSize(new Dimension(500, 70));
        table.setFillsViewportHeight(true);

        /*
         * Si debug esta en verdadero, cada vez que demos click a una fila, se nos desplegara
         * en el output la información contenida en la tablas
         */
        if (DEBUG) {
            table.addMouseListener(new MouseAdapter() {

                public void mouseClicked(MouseEvent e) {
                    printDebugData(table);
                }
            });
        }

        //Create the scroll pane and add the table to it.
        JScrollPane scrollPane = new JScrollPane(table);

        //Add the scroll pane to this panel.
        add(scrollPane);
    }

    /**
     * se muestra la manera de recorrer la tabla, para obtener la infromación de cada fila
     */
    private void printDebugData(JTable table) {
        int numRows = table.getRowCount();
        int numCols = table.getColumnCount();
        javax.swing.table.TableModel model = table.getModel();

        System.out.println("Value of data: ");
        for (int i = 0; i < numRows; i++) {
            System.out.print("    row " + i + ":");
            for (int j = 0; j < numCols; j++) {
                System.out.print("  " + model.getValueAt(i, j));//Devuelve el valor contenida en una celda, especificada por Fila-Columna
            }
            System.out.println();
        }
        System.out.println("--------------------------");
    }

    /**
     * Procedimiento que cree la interfaz gráfica
     */
    private static void createAndShowGUI() {
        //Create and set up the window.
        JFrame frame = new JFrame("SimpleTableDemo");
        frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);

        //Create and set up the content pane.
        SimpleTableDemo newContentPane = new SimpleTableDemo();
        newContentPane.setOpaque(true); //content panes must be opaque
        frame.setContentPane(newContentPane);

        //Display the window.
        frame.pack();
        frame.setVisible(true);
    }

    public static void main(String[] args) {
        javax.swing.SwingUtilities.invokeLater(new Runnable() {

            public void run() {
                createAndShowGUI();
            }
        });
    }
}


JTree
El JTree nos permite mostrar información jerárquica, es excelente para mostrar datos como un árbol familiar o la estructura del sistema de archivos. Utilizar un JTree es algo sencillo, pero no siempre es muy claro cómo llenarlo para no gastar mucha memoria y para que no se gaste mucho tiempo al llenarlo. En este Trial vamos a hacer una aplicación guiada en la que utilizaremos un JTree para mostrar el sistema de archivos de la partición raíz de la computadora.

Ejemplo:
import javax.swing.JFrame;
import javax.swing.JScrollPane;
import javax.swing.JTree;
import javax.swing.WindowConstants;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.DefaultTreeModel;

public class PruebaJTree4
{
    /**
     * Ejemplo sencillo de uso de JTree
     *
     * @param args Argumentos de linea de comandos. Se ignoran.
     */
    public static void main(String[] args)
    {
        // Construccion del arbol
        DefaultMutableTreeNode abuelo = new DefaultMutableTreeNode("abuelo");
        DefaultTreeModel modelo = new DefaultTreeModel(abuelo);
        JTree tree = new JTree(modelo);

        // Hacemos el árbol editable y le ponemos nuestro propio editor
        tree.setEditable(true);
        tree.setCellEditor(new MiTreeEditor());

        // Construccion de los datos del arbol
        DefaultMutableTreeNode padre = new DefaultMutableTreeNode("padre");
        DefaultMutableTreeNode tio = new DefaultMutableTreeNode("tio");
        modelo.insertNodeInto(padre, abuelo, 0);
        modelo.insertNodeInto(tio, abuelo, 1);

        DefaultMutableTreeNode hijo = new DefaultMutableTreeNode("hijo");
        DefaultMutableTreeNode hija = new DefaultMutableTreeNode("hija");
        modelo.insertNodeInto(hijo, padre, 0);
        modelo.insertNodeInto(hija, padre, 1);

        // Construccion y visualizacion de la ventana
        JFrame v = new JFrame();
        JScrollPane scroll = new JScrollPane(tree);
        v.getContentPane().add(scroll);
        v.pack();
        v.setVisible(true);
        v.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
    }
}






import java.awt.Component;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.event.MouseEvent;
import java.util.EventObject;
import java.util.Iterator;
import java.util.LinkedList;

import javax.swing.JComboBox;
import javax.swing.JTree;
import javax.swing.event.CellEditorListener;
import javax.swing.event.ChangeEvent;
import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeCellEditor;


public class MiTreeEditor extends JComboBox implements TreeCellEditor
{
    /**
   * Serial uid
   */
  private static final long serialVersionUID = 7821334334936220578L;

  /**
     * Lista de suscriptores a eventos de edición
     */
    private LinkedList<CellEditorListener> observadores = new LinkedList<CellEditorListener>();

    /**
     * Crea un nuevo objeto MiTreeEditor.
     */
    public MiTreeEditor()
    {
      // Posibles items del JComboBox
        addItem("abuelo");
        addItem("padre");
        addItem("hijo");
        addItem("hija");
        addItem("tio");

        // Listener para enterarnos de cuando el usuario selecciona algún item
        addActionListener(
            new ActionListener()
            {
                public void actionPerformed(ActionEvent arg0)
                {
                  // Cuando el usuario selecciona el item, avisamos a los
                  // suscriptores de que la edición ha terminado.
                    Iterator<CellEditorListener> iterador = observadores.iterator();

                    while (iterador.hasNext())
                    {
                        iterador.next().editingStopped(
                            new ChangeEvent(MiTreeEditor.this));
                    }
                }
            });
    }

    /**
     * Devuelve el Component que se usará para editar el dato.
     *
     * @param tree JTree en el que está el dato que se va a editar
     * @param value El dato a editar. Este valor debe meterse en el Component
     * que se usa para editar, de forma que sea el que se muestre.
     * @param isSelected Si el dato está seleccionado en el JTree
     * @param expanded Si el nodo del dato está expandido
     * @param leaf Si el nodo del dato es hoja (no tiene hijos)
     * @param row Fila del JTree en el que está el dato.
     *
     * @return El Component que hace de editor, mostrando value.
     */
    public Component getTreeCellEditorComponent(
        JTree tree, Object value, boolean isSelected, boolean expanded,
        boolean leaf, int row)
    {
      // Se marca el contenido de value como dato a mostrar en el JComboBox
        setSelectedItem(
            ((DefaultMutableTreeNode) value).getUserObject().toString());

        return this;
    }

    /**
     * Añade un nuevo suscriptor a cambios en el editor.
     *
     * @param l Un suscriptor
     */
    public void addCellEditorListener(CellEditorListener l)
    {
        observadores.add(l);
    }

    /**
     * El JTree nos avisa de que se ha cancelado la edición, por ejemplo, el usuario
     * ha pinchado con el ratón en otro nodo sin terminar de editar el nuestro.
     */
    public void cancelCellEditing()
    {
      // No necesitamos hacer ninguna acción especial si se cancela la edición
    }

    /**
     * Debemos devolver el dato que ha recogido el editor
     *
     * @return El dato.
     */
    public Object getCellEditorValue()
    {
        return getSelectedItem();
    }

    /**
     * Nos pasan el evento que ha sucedido sobre el nodo y debemos decidir si es
     * un evento para empezar a editar o no.
     * En este ejemplo se comprobará si es un triple click de ratón. El doble click
     * ya lo tiene reservado el JTree para expandir/contraer nodos.
     *
     * @param anEvent Evento.
     *
     * @return true si se debe empezar a editar el nodo.
     */
    public boolean isCellEditable(EventObject anEvent)
    {
      // Se comprueba si el evento es un evento de ratón
        if (anEvent instanceof MouseEvent)
        {
          // Y si es tripe click
            if (((MouseEvent) anEvent).getClickCount() == 3)
            {
                return true;
            }
        }

        // En caso contrario no hay que editar.
        return false;
    }

    /**
     * Borra al suscriptor de la lista de suscriptores
     *
     * @param l Suscriptores
     */
    public void removeCellEditorListener(CellEditorListener l)
    {
        observadores.remove(l);
    }

    /**
     * Para decidir si cuando se edita una celda, debe a su vez seleccionarse.
     * Habitualmente se devuelve true, ya que al editar se suele querer que se
     * seleccione.
     * Se pude devolver false si se quiere editar una celda sin que se deseleccionen
     * otras posibles celdas del JTree que estuvieran seleccionadas y sin que se
     * seleccione la celda que estamos editando.
     *
     * @param anEvent Evento que ha ocurrido sobre la celda.
     *
     * @return true si queremos que se seleccione.
     */
    public boolean shouldSelectCell(EventObject anEvent)
    {
        return true;
    }

    /**
     * Nos avisan que debemos detener la edición y aceptar el valor que haya en
     * el editor.
     * Debemos devolver true si el valor del editor es valido y lo aceptamos. false
     * en caso de que ese valor no sea correcto y no debamos aceptar la edicion.
     *
     * @return true
     */
    public boolean stopCellEditing()
    {
      // No necesitamos hacer nada especial si se para la edición
      return true;
    }
}